]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge tag 'newsoc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Jul 2012 23:31:31 +0000 (16:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Jul 2012 23:31:31 +0000 (16:31 -0700)
Pull support for three new arm SoC types from Arnd Bergmann:

 - The mvebu platform includes Marvell's Armada XP and Armada 370 chips,
   made by the mvebu business unit inside of Marvell.  Since the same
   group also made the older but similar platforms we call "orion5x",
   "kirkwood", "mv78xx0" and "dove", we plan to move all of them into
   the mach-mvebu directory in the future.

 - socfpga is Altera's platform based on Cortex-A9 cores and a lot of
   FPGA space.  This is similar to the Xilinx zynq platform we already
   support.  The code is particularly clean, which is helped by the fact
   that the hardware doesn't do much besides the parts that are expected
   to get added in the FPGA.

 - The OMAP subarchitecture gains support for the latest generation, the
   OMAP5 based on the new Cortex-A15 core.  Support is rather
   rudimentary for now, but will be extended in the future.

* tag 'newsoc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (25 commits)
  ARM: socfpga: initial support for Altera's SOCFPGA platform
  arm: mvebu: generate DTBs for supported SoCs
  ARM: mvebu: MPIC: read number of interrupts from control register
  arm: mach-mvebu: add entry to MAINTAINERS
  arm: mach-mvebu: add compilation/configuration change
  arm: mach-mvebu: add defconfig
  arm: mach-mvebu: add documentation for new device tree bindings
  arm: mach-mvebu: add support for Armada 370 and Armada XP with DT
  arm: mach-mvebu: add source files
  arm: mach-mvebu: add header
  clocksource: time-armada-370-xp: Marvell Armada 370/XP SoC timer driver
  ARM: Kconfig update to support additional GPIOs in OMAP5
  ARM: OMAP5: Add the build support
  arm/dts: OMAP5: Add omap5 dts files
  ARM: OMAP5: board-generic: Add device tree support
  ARM: omap2+: board-generic: clean up the irq data from board file
  ARM: OMAP5: Add SMP support
  ARM: OMAP5: Add the WakeupGen IP updates
  ARM: OMAP5: l3: Add l3 error handler support for omap5
  ARM: OMAP5: gpmc: Update gpmc_init()
  ...

Conflicts:
Documentation/devicetree/bindings/arm/omap/omap.txt
arch/arm/mach-omap2/Makefile
drivers/clocksource/Kconfig
drivers/clocksource/Makefile

1522 files changed:
Documentation/ABI/testing/sysfs-block-rssd
Documentation/ABI/testing/sysfs-class-mtd
Documentation/ABI/testing/sysfs-power
Documentation/DocBook/media/v4l/controls.xml
Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
Documentation/RCU/checklist.txt
Documentation/RCU/rcubarrier.txt
Documentation/RCU/torture.txt
Documentation/RCU/whatisRCU.txt
Documentation/device-mapper/verity.txt
Documentation/devicetree/bindings/arm/atmel-aic.txt
Documentation/devicetree/bindings/arm/davinci/cp-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/olimex.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/omap/omap.txt
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt [moved from Documentation/devicetree/bindings/arm/tegra/emc.txt with 99% similarity]
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
Documentation/devicetree/bindings/fb/mxsfb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/fsl-imx-gpio.txt
Documentation/devicetree/bindings/gpio/gpio-mxs.txt
Documentation/devicetree/bindings/gpio/gpio-nmk.txt
Documentation/devicetree/bindings/gpio/nvidia,tegra20-gpio.txt [moved from Documentation/devicetree/bindings/gpio/gpio_nvidia.txt with 100% similarity]
Documentation/devicetree/bindings/input/fsl-mma8450.txt
Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt [moved from Documentation/devicetree/bindings/input/tegra-kbc.txt with 100% similarity]
Documentation/devicetree/bindings/mfd/mc13xxx.txt
Documentation/devicetree/bindings/mfd/tps65910.txt
Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/mmci.txt
Documentation/devicetree/bindings/mmc/mxs-mmc.txt
Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt [moved from Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt with 67% similarity]
Documentation/devicetree/bindings/mmc/sdhci-pxa.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
Documentation/devicetree/bindings/net/fsl-fec.txt
Documentation/devicetree/bindings/nvec/nvidia,nvec.txt [moved from Documentation/devicetree/bindings/nvec/nvec_nvidia.txt with 100% similarity]
Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt
Documentation/devicetree/bindings/regulator/fixed-regulator.txt
Documentation/devicetree/bindings/regulator/regulator.txt
Documentation/devicetree/bindings/regulator/tps65217.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/tps6586x.txt
Documentation/devicetree/bindings/regulator/twl-regulator.txt
Documentation/devicetree/bindings/rtc/dw-apb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt [moved from Documentation/devicetree/bindings/sound/tegra-audio-alc5632.txt with 100% similarity]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-trimslice.txt [moved from Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt with 100% similarity]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt [moved from Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt with 100% similarity]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt [moved from Documentation/devicetree/bindings/sound/tegra-audio-wm8903.txt with 100% similarity]
Documentation/devicetree/bindings/sound/nvidia,tegra20-das.txt [moved from Documentation/devicetree/bindings/sound/tegra20-das.txt with 100% similarity]
Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt [moved from Documentation/devicetree/bindings/sound/tegra20-i2s.txt with 100% similarity]
Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
Documentation/devicetree/bindings/spi/nvidia,tegra20-spi.txt [moved from Documentation/devicetree/bindings/spi/spi_nvidia.txt with 100% similarity]
Documentation/devicetree/bindings/spi/spi-samsung.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt [moved from Documentation/devicetree/bindings/usb/tegra-usb.txt with 100% similarity]
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/devicetree/bindings/watchdog/omap-wdt.txt [new file with mode: 0644]
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
Documentation/kdump/kdump.txt
Documentation/kernel-parameters.txt
Documentation/power/devices.txt
Documentation/power/swsusp.txt
Documentation/prctl/no_new_privs.txt [new file with mode: 0644]
Documentation/virtual/kvm/api.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/boot/dts/aks-cdu.dts [new file with mode: 0644]
arch/arm/boot/dts/am335x-bone.dts [new file with mode: 0644]
arch/arm/boot/dts/am335x-evm.dts [new file with mode: 0644]
arch/arm/boot/dts/am33xx.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am3517-evm.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/db8500.dtsi
arch/arm/boot/dts/ea3250.dts [new file with mode: 0644]
arch/arm/boot/dts/evk-pro3.dts [new file with mode: 0644]
arch/arm/boot/dts/exynos4210-origen.dts
arch/arm/boot/dts/exynos4210-smdkv310.dts
arch/arm/boot/dts/exynos4210.dtsi
arch/arm/boot/dts/exynos5250-smdk5250.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/ge863-pro3.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx23-evk.dts
arch/arm/boot/dts/imx23-olinuxino.dts [new file with mode: 0644]
arch/arm/boot/dts/imx23-stmp378x_devb.dts [new file with mode: 0644]
arch/arm/boot/dts/imx23.dtsi
arch/arm/boot/dts/imx27-3ds.dts [new file with mode: 0644]
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx28-apx4devkit.dts [new file with mode: 0644]
arch/arm/boot/dts/imx28-cfa10036.dts [new file with mode: 0644]
arch/arm/boot/dts/imx28-evk.dts
arch/arm/boot/dts/imx28-m28evk.dts [new file with mode: 0644]
arch/arm/boot/dts/imx28-tx28.dts [new file with mode: 0644]
arch/arm/boot/dts/imx28.dtsi
arch/arm/boot/dts/imx31-bug.dts [new file with mode: 0644]
arch/arm/boot/dts/imx31.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6q-arm2.dts
arch/arm/boot/dts/imx6q-sabrelite.dts
arch/arm/boot/dts/imx6q.dtsi
arch/arm/boot/dts/lpc32xx.dtsi
arch/arm/boot/dts/omap2420-h4.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3-beagle.dts
arch/arm/boot/dts/omap3-evm.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap4-panda.dts
arch/arm/boot/dts/omap4-pandaES.dts [new file with mode: 0644]
arch/arm/boot/dts/omap4-sdp.dts
arch/arm/boot/dts/omap4-var_som.dts [new file with mode: 0644]
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/phy3250.dts
arch/arm/boot/dts/snowball.dts
arch/arm/boot/dts/spear13xx.dtsi
arch/arm/boot/dts/spear320-evb.dts
arch/arm/boot/dts/spear600.dtsi
arch/arm/boot/dts/tegra20-harmony.dts [moved from arch/arm/boot/dts/tegra-harmony.dts with 99% similarity]
arch/arm/boot/dts/tegra20-paz00.dts [moved from arch/arm/boot/dts/tegra-paz00.dts with 99% similarity]
arch/arm/boot/dts/tegra20-seaboard.dts [moved from arch/arm/boot/dts/tegra-seaboard.dts with 88% similarity]
arch/arm/boot/dts/tegra20-trimslice.dts [moved from arch/arm/boot/dts/tegra-trimslice.dts with 100% similarity]
arch/arm/boot/dts/tegra20-ventana.dts [moved from arch/arm/boot/dts/tegra-ventana.dts with 99% similarity]
arch/arm/boot/dts/tegra20-whistler.dts [new file with mode: 0644]
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30-cardhu.dts [moved from arch/arm/boot/dts/tegra-cardhu.dts with 99% similarity]
arch/arm/boot/dts/tegra30.dtsi
arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
arch/arm/boot/dts/vexpress-v2m.dtsi
arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts [new file with mode: 0644]
arch/arm/configs/lpc32xx_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/include/asm/atomic.h
arch/arm/include/asm/domain.h
arch/arm/include/asm/thread_info.h
arch/arm/kernel/irq.c
arch/arm/kernel/kprobes-test-arm.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/signal.c
arch/arm/kernel/signal.h
arch/arm/kernel/traps.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile.boot
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam926x_time.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/at91sam9x5.c
arch/arm/mach-at91/at91x40.c
arch/arm/mach-at91/board-1arm.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-carmeva.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-csb337.c
arch/arm/mach-at91/board-csb637.c
arch/arm/mach-at91/board-dt.c
arch/arm/mach-at91/board-eb01.c
arch/arm/mach-at91/board-eb9200.c
arch/arm/mach-at91/board-ecbat91.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-foxg20.c
arch/arm/mach-at91/board-gsia18s.c
arch/arm/mach-at91/board-kafa.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-pcontrol-g20.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-rm9200dk.c
arch/arm/mach-at91/board-rm9200ek.c
arch/arm/mach-at91/board-rsi-ews.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a926x.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/gpio.c
arch/arm/mach-at91/include/mach/at91_aic.h
arch/arm/mach-at91/include/mach/at91_spi.h [deleted file]
arch/arm/mach-at91/include/mach/at91_ssc.h [deleted file]
arch/arm/mach-at91/include/mach/entry-macro.S [deleted file]
arch/arm/mach-at91/include/mach/irqs.h [deleted file]
arch/arm/mach-at91/irq.c
arch/arm/mach-at91/pm.c
arch/arm/mach-clps711x/common.c
arch/arm/mach-clps711x/include/mach/memory.h
arch/arm/mach-clps711x/p720t.c
arch/arm/mach-davinci/Kconfig
arch/arm/mach-davinci/Makefile
arch/arm/mach-davinci/cp_intc.c
arch/arm/mach-davinci/include/mach/cp_intc.h
arch/arm/mach-davinci/include/mach/dm365.h [deleted file]
arch/arm/mach-davinci/include/mach/dm646x.h [deleted file]
arch/arm/mach-davinci/include/mach/entry-macro.S
arch/arm/mach-davinci/pm_domain.c [new file with mode: 0644]
arch/arm/mach-dove/include/mach/bridge-regs.h
arch/arm/mach-dove/include/mach/dove.h
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/include/mach/platform.h
arch/arm/mach-ep93xx/soc.h
arch/arm/mach-exynos/clock-exynos4.c
arch/arm/mach-exynos/clock-exynos5.c
arch/arm/mach-exynos/common.c
arch/arm/mach-exynos/include/mach/irqs.h
arch/arm/mach-exynos/include/mach/map.h
arch/arm/mach-exynos/include/mach/regs-pmu.h
arch/arm/mach-exynos/include/mach/regs-usb-phy.h
arch/arm/mach-exynos/include/mach/spi-clocks.h [deleted file]
arch/arm/mach-exynos/mach-exynos4-dt.c
arch/arm/mach-exynos/mach-exynos5-dt.c
arch/arm/mach-exynos/mach-nuri.c
arch/arm/mach-exynos/mach-origen.c
arch/arm/mach-exynos/mach-smdkv310.c
arch/arm/mach-exynos/mach-universal_c210.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-exynos/pmu.c
arch/arm/mach-exynos/setup-spi.c
arch/arm/mach-exynos/setup-usb-phy.c
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/clk-imx31.c
arch/arm/mach-imx/clk-imx35.c
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/devices-imx21.h
arch/arm/mach-imx/devices-imx25.h
arch/arm/mach-imx/devices-imx27.h
arch/arm/mach-imx/devices-imx31.h
arch/arm/mach-imx/devices-imx35.h
arch/arm/mach-imx/devices-imx51.h
arch/arm/mach-imx/devices-imx53.h
arch/arm/mach-imx/ehci-imx25.c
arch/arm/mach-imx/ehci-imx35.c
arch/arm/mach-imx/ehci-imx5.c
arch/arm/mach-imx/imx27-dt.c
arch/arm/mach-imx/imx31-dt.c [new file with mode: 0644]
arch/arm/mach-imx/mach-cpuimx27.c
arch/arm/mach-imx/mach-cpuimx35.c
arch/arm/mach-imx/mach-cpuimx51sd.c
arch/arm/mach-imx/mach-eukrea_cpuimx25.c
arch/arm/mach-imx/mach-imx27_visstrim_m10.c
arch/arm/mach-imx/mach-imx27ipcam.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/mach-mx25_3ds.c
arch/arm/mach-imx/mach-mx27_3ds.c
arch/arm/mach-imx/mach-mx27ads.c
arch/arm/mach-imx/mach-mx31_3ds.c
arch/arm/mach-imx/mach-mx31moboard.c
arch/arm/mach-imx/mach-mx35_3ds.c
arch/arm/mach-imx/mach-mx51_3ds.c
arch/arm/mach-imx/mach-mx51_babbage.c
arch/arm/mach-imx/mach-mx53_ard.c
arch/arm/mach-imx/mach-mx53_evk.c
arch/arm/mach-imx/mach-mx53_loco.c
arch/arm/mach-imx/mach-mx53_smd.c
arch/arm/mach-imx/mach-pca100.c
arch/arm/mach-imx/mach-pcm037.c
arch/arm/mach-imx/mach-pcm038.c
arch/arm/mach-imx/mach-pcm043.c
arch/arm/mach-imx/mach-qong.c
arch/arm/mach-imx/mach-vpr200.c
arch/arm/mach-imx/mx31lite-db.c
arch/arm/mach-lpc32xx/Kconfig [deleted file]
arch/arm/mach-lpc32xx/Makefile.boot
arch/arm/mach-lpc32xx/clock.c
arch/arm/mach-lpc32xx/common.c
arch/arm/mach-lpc32xx/include/mach/gpio.h
arch/arm/mach-lpc32xx/include/mach/platform.h
arch/arm/mach-lpc32xx/phy3250.c
arch/arm/mach-lpc32xx/serial.c
arch/arm/mach-mmp/include/mach/gpio-pxa.h [deleted file]
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
arch/arm/mach-mxs/Kconfig
arch/arm/mach-mxs/Makefile.boot
arch/arm/mach-mxs/devices-mx23.h
arch/arm/mach-mxs/devices-mx28.h
arch/arm/mach-mxs/devices/platform-mxsfb.c
arch/arm/mach-mxs/mach-apx4devkit.c
arch/arm/mach-mxs/mach-mxs.c
arch/arm/mach-mxs/module-tx28.c
arch/arm/mach-nomadik/Makefile
arch/arm/mach-nomadik/board-nhk8815.c
arch/arm/mach-nomadik/clock.c [deleted file]
arch/arm/mach-nomadik/clock.h [deleted file]
arch/arm/mach-nomadik/cpu-8815.c
arch/arm/mach-nomadik/i2c-8815nhk.c
arch/arm/mach-nomadik/include/mach/irqs.h
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/am35xx-emac.c
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3logic.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/clock3xxx_data.c
arch/arm/mach-omap2/clockdomain.h
arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
arch/arm/mach-omap2/clockdomains3xxx_data.c
arch/arm/mach-omap2/clockdomains44xx_data.c
arch/arm/mach-omap2/cm-regbits-34xx.h
arch/arm/mach-omap2/common-board-devices.c
arch/arm/mach-omap2/cpuidle34xx.c
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/include/mach/am35xx.h
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/omap-iommu.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/opp.c
arch/arm/mach-omap2/pm.h
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/powerdomains3xxx_data.c
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prm_common.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-picoxcell/Makefile
arch/arm/mach-picoxcell/common.c
arch/arm/mach-picoxcell/common.h
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-s3c24xx/clock-s3c2416.c
arch/arm/mach-s3c24xx/clock-s3c2440.c
arch/arm/mach-s3c24xx/clock-s3c2443.c
arch/arm/mach-s3c24xx/common-s3c2443.c
arch/arm/mach-s3c24xx/common-smdk.c
arch/arm/mach-s3c24xx/common.c
arch/arm/mach-s3c24xx/include/mach/bast-pmu.h [deleted file]
arch/arm/mach-s3c24xx/include/mach/gpio-nrs.h
arch/arm/mach-s3c24xx/include/mach/gta02.h
arch/arm/mach-s3c24xx/include/mach/regs-gpio.h
arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h [deleted file]
arch/arm/mach-s3c24xx/mach-gta02.c
arch/arm/mach-s3c24xx/mach-mini2440.c
arch/arm/mach-s3c24xx/mach-qt2410.c
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/arm/mach-s3c24xx/pm-s3c2410.c
arch/arm/mach-s3c24xx/pm-s3c2412.c
arch/arm/mach-s3c24xx/s3c2412.c
arch/arm/mach-s3c24xx/s3c244x.c
arch/arm/mach-s3c24xx/setup-spi.c
arch/arm/mach-s3c24xx/setup-ts.c
arch/arm/mach-s3c64xx/clock.c
arch/arm/mach-s3c64xx/include/mach/dma.h
arch/arm/mach-s3c64xx/include/mach/spi-clocks.h [deleted file]
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/setup-spi.c
arch/arm/mach-s5p64x0/clock-s5p6440.c
arch/arm/mach-s5p64x0/clock-s5p6450.c
arch/arm/mach-s5p64x0/dma.c
arch/arm/mach-s5p64x0/include/mach/spi-clocks.h [deleted file]
arch/arm/mach-s5p64x0/setup-spi.c
arch/arm/mach-s5pc100/clock.c
arch/arm/mach-s5pc100/dma.c
arch/arm/mach-s5pc100/include/mach/spi-clocks.h [deleted file]
arch/arm/mach-s5pc100/setup-spi.c
arch/arm/mach-s5pv210/clock.c
arch/arm/mach-s5pv210/include/mach/spi-clocks.h [deleted file]
arch/arm/mach-s5pv210/setup-spi.c
arch/arm/mach-shmobile/platsmp.c
arch/arm/mach-spear3xx/spear3xx.c
arch/arm/mach-spear6xx/spear6xx.c
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/Makefile.boot
arch/arm/mach-tegra/apbio.c
arch/arm/mach-tegra/apbio.h
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/cpuidle.c
arch/arm/mach-tegra/sleep.S
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-mop500.h
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/timer.c
arch/arm/mach-versatile/pci.c
arch/arm/mach-vexpress/Kconfig
arch/arm/mach-vexpress/Makefile.boot
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mach-vexpress/include/mach/clkdev.h [deleted file]
arch/arm/mach-vexpress/include/mach/debug-macro.S
arch/arm/mach-vexpress/include/mach/motherboard.h
arch/arm/mach-vexpress/include/mach/uncompress.h
arch/arm/mach-vexpress/v2m.c
arch/arm/mach-vt8500/Makefile
arch/arm/mach-vt8500/bv07.c
arch/arm/mach-vt8500/include/mach/restart.h [new file with mode: 0644]
arch/arm/mach-vt8500/include/mach/system.h [deleted file]
arch/arm/mach-vt8500/restart.c [new file with mode: 0644]
arch/arm/mach-vt8500/wm8505_7in.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/plat-mxc/devices/platform-mxc_rtc.c
arch/arm/plat-mxc/include/mach/common.h
arch/arm/plat-mxc/include/mach/iomux-mx51.h
arch/arm/plat-mxc/include/mach/mxc_ehci.h
arch/arm/plat-omap/include/plat/cpu.h
arch/arm/plat-omap/include/plat/mux.h
arch/arm/plat-omap/include/plat/omap730.h [deleted file]
arch/arm/plat-omap/include/plat/omap850.h [deleted file]
arch/arm/plat-omap/mailbox.c
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/adc.c
arch/arm/plat-samsung/devs.c
arch/arm/plat-samsung/dma-ops.c
arch/arm/plat-samsung/include/plat/cpu.h
arch/arm/plat-samsung/include/plat/devs.h
arch/arm/plat-samsung/include/plat/dma-ops.h
arch/arm/plat-samsung/include/plat/fb.h
arch/arm/plat-samsung/include/plat/pd.h [deleted file]
arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
arch/arm/plat-samsung/pd.c [deleted file]
arch/arm/plat-samsung/pwm.c
arch/arm/plat-samsung/s3c-dma-ops.c
arch/arm/plat-samsung/s5p-clock.c
arch/arm/plat-versatile/Kconfig
arch/arm/plat-versatile/Makefile
arch/h8300/include/asm/pgtable.h
arch/h8300/include/asm/uaccess.h
arch/h8300/kernel/signal.c
arch/h8300/kernel/time.c
arch/hexagon/kernel/smp.c
arch/ia64/kernel/smpboot.c
arch/m32r/boot/compressed/Makefile
arch/m32r/boot/compressed/misc.c
arch/m32r/include/asm/ptrace.h
arch/m32r/include/asm/smp.h
arch/m32r/kernel/ptrace.c
arch/m32r/kernel/signal.c
arch/mips/Kconfig
arch/mips/bcm47xx/Kconfig
arch/mips/bcm63xx/dev-pcmcia.c
arch/mips/cavium-octeon/Kconfig
arch/mips/cavium-octeon/smp.c
arch/mips/include/asm/bitops.h
arch/mips/include/asm/cmpxchg.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/gic.h
arch/mips/include/asm/inst.h
arch/mips/include/asm/io.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
arch/mips/include/asm/mips-boards/maltaint.h
arch/mips/include/asm/mipsmtregs.h
arch/mips/include/asm/switch_to.h
arch/mips/include/asm/thread_info.h
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/mips_ksyms.c
arch/mips/kernel/octeon_switch.S
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp.c
arch/mips/kernel/smtc.c
arch/mips/kernel/sync-r4k.c
arch/mips/kernel/traps.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/mm/Makefile
arch/mips/mm/c-r4k.c
arch/mips/mm/page-funcs.S [new file with mode: 0644]
arch/mips/mm/page.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-pci.c
arch/mips/mti-malta/malta-setup.c
arch/mips/netlogic/xlp/setup.c
arch/mips/oprofile/common.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pci/fixup-fuloong2e.c
arch/mips/pci/fixup-lemote2f.c
arch/mips/pci/fixup-malta.c
arch/mips/pci/fixup-mpc30x.c
arch/mips/pci/fixup-sb1250.c
arch/mips/pci/ops-tx4927.c
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-lantiq.c
arch/mips/pci/pci-xlr.c
arch/mips/pmc-sierra/yosemite/smp.c
arch/mips/powertv/asic/asic-calliope.c
arch/mips/powertv/asic/asic-cronus.c
arch/mips/powertv/asic/asic-gaia.c
arch/mips/powertv/asic/asic-zeus.c
arch/mips/txx9/generic/pci.c
arch/mn10300/include/asm/ptrace.h
arch/mn10300/include/asm/thread_info.h
arch/mn10300/include/asm/timex.h
arch/mn10300/kernel/cevt-mn10300.c
arch/mn10300/kernel/internal.h
arch/mn10300/kernel/irq.c
arch/mn10300/kernel/signal.c
arch/mn10300/kernel/smp.c
arch/mn10300/kernel/traps.c
arch/mn10300/mm/dma-alloc.c
arch/mn10300/unit-asb2303/include/unit/timex.h
arch/mn10300/unit-asb2303/smc91111.c
arch/mn10300/unit-asb2305/include/unit/timex.h
arch/mn10300/unit-asb2305/unit-init.c
arch/mn10300/unit-asb2364/include/unit/timex.h
arch/parisc/kernel/smp.c
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/smp.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_pr_papr.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/cell/pervasive.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/pseries/processor_idle.c
arch/powerpc/xmon/xmon.c
arch/s390/kernel/smp.c
arch/sh/include/asm/io_noioport.h
arch/sh/kernel/cpu/sh3/serial-sh7720.c
arch/sparc/kernel/smp_64.c
arch/tile/kernel/backtrace.c
arch/tile/kernel/smpboot.c
arch/um/drivers/mconsole_kern.c
arch/x86/Makefile
arch/x86/include/asm/alternative.h
arch/x86/include/asm/amd_nb.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/emergency-restart.h
arch/x86/include/asm/floppy.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/msr.h
arch/x86/include/asm/nmi.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/pgtable-2level.h
arch/x86/include/asm/pgtable-3level.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/realmode.h
arch/x86/include/asm/reboot.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/uaccess_64.h
arch/x86/include/asm/uprobes.h
arch/x86/include/asm/uv/uv_bau.h
arch/x86/include/asm/x2apic.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_nb.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/io_apic.c
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/apic/probe_32.c
arch/x86/kernel/apic/probe_64.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/apm_32.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/mtrr/cleanup.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c [new file with mode: 0644]
arch/x86/kernel/cpu/perf_event_intel_uncore.h [new file with mode: 0644]
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/cpu/perf_event_p6.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/dumpstack_32.c
arch/x86/kernel/dumpstack_64.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/irq.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/module.c
arch/x86/kernel/nmi.c
arch/x86/kernel/nmi_selftest.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/process.c
arch/x86/kernel/process_64.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/uprobes.c
arch/x86/kernel/vm86_32.c
arch/x86/kernel/vsmp_64.c
arch/x86/kernel/vsyscall_64.c
arch/x86/kernel/x8664_ksyms_64.c
arch/x86/kernel/x86_init.c
arch/x86/kernel/xsave.c
arch/x86/kvm/mmu.c
arch/x86/kvm/pmu.c
arch/x86/kvm/trace.h
arch/x86/lib/msr-reg-export.c
arch/x86/lib/msr-reg.S
arch/x86/mm/init.c
arch/x86/oprofile/op_model_amd.c
arch/x86/platform/olpc/olpc-xo15-sci.c
arch/x86/platform/uv/tlb_uv.c
arch/x86/platform/uv/uv_irq.c
arch/x86/realmode/rm/Makefile
arch/x86/realmode/rm/header.S
arch/x86/realmode/rm/reboot.S [moved from arch/x86/realmode/rm/reboot_32.S with 85% similarity]
arch/x86/vdso/vdso32-setup.c
arch/x86/xen/enlighten.c
arch/x86/xen/smp.c
arch/xtensa/kernel/process.c
block/blk-cgroup.c
block/blk-core.c
block/blk-timeout.c
block/cfq-iosched.c
block/scsi_ioctl.c
drivers/acpi/ac.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/battery.c
drivers/acpi/button.c
drivers/acpi/fan.c
drivers/acpi/power.c
drivers/acpi/processor_core.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_idle.c
drivers/acpi/sbs.c
drivers/acpi/scan.c
drivers/acpi/thermal.c
drivers/amba/tegra-ahb.c
drivers/base/dd.c
drivers/base/devtmpfs.c
drivers/base/power/domain.c
drivers/base/power/main.c
drivers/base/power/qos.c
drivers/base/power/sysfs.c
drivers/base/regmap/internal.h
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-mmio.c
drivers/base/regmap/regmap.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_req.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/mg_disk.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/mtip32xx/mtip32xx.h
drivers/block/rbd.c
drivers/block/umem.c
drivers/block/xen-blkback/common.h
drivers/block/xen-blkfront.c
drivers/char/hw_random/omap-rng.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/sonypi.c
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_atmel.c
drivers/char/tpm/tpm_nsc.c
drivers/char/tpm/tpm_tis.c
drivers/clk/Makefile
drivers/clk/clk-nomadik.c [new file with mode: 0644]
drivers/clk/clk.c
drivers/clk/spear/spear1310_clock.c
drivers/clk/spear/spear1340_clock.c
drivers/clk/spear/spear3xx_clock.c
drivers/clk/spear/spear6xx_clock.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/dw_apb_timer_of.c [moved from arch/arm/mach-picoxcell/time.c with 57% similarity]
drivers/cpufreq/cpufreq.c
drivers/cpufreq/exynos-cpufreq.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/driver.c
drivers/cpuidle/governors/menu.c
drivers/cpuidle/sysfs.c
drivers/crypto/ux500/cryp/cryp_core.c
drivers/crypto/ux500/hash/hash_core.c
drivers/gpio/Kconfig
drivers/gpio/devres.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-sta2x11.c
drivers/gpio/gpio-tps65910.c
drivers/gpio/gpio-wm8994.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/opregion.c
drivers/gpu/drm/gma500/opregion.h
drivers/gpu/drm/gma500/psb_device.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/si.c
drivers/hid/Kconfig
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-multitouch.c
drivers/hid/usbhid/hid-quirks.c
drivers/hwmon/acpi_power_meter.c
drivers/hwmon/it87.c
drivers/hwmon/k10temp.c
drivers/hwspinlock/hwspinlock_core.c
drivers/i2c/busses/i2c-nomadik.c
drivers/idle/intel_idle.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/joystick/as5011.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/mcs_touchkey.c
drivers/input/keyboard/mpr121_touchkey.c
drivers/input/keyboard/qt1070.c
drivers/input/keyboard/tca6416-keypad.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/keyboard/tnetv107x-keypad.c
drivers/input/misc/ad714x.c
drivers/input/misc/dm355evm_keys.c
drivers/input/mouse/bcm5974.c
drivers/input/tablet/wacom_sys.c
drivers/input/touchscreen/ad7879.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/intel-mid-touch.c
drivers/input/touchscreen/pixcir_i2c_ts.c
drivers/input/touchscreen/tnetv107x-ts.c
drivers/input/touchscreen/tsc2005.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_types.h
drivers/iommu/dmar.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/irq_remapping.c
drivers/iommu/irq_remapping.h
drivers/iommu/tegra-smmu.c
drivers/isdn/mISDN/stack.c
drivers/leds/ledtrig-heartbeat.c
drivers/md/dm-raid1.c
drivers/md/dm-region-hash.c
drivers/md/dm-thin.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/persistent-data/dm-space-map-checker.c
drivers/md/persistent-data/dm-space-map-disk.c
drivers/md/persistent-data/dm-transaction-manager.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/rc/winbond-cir.c
drivers/media/video/cx231xx/cx231xx-audio.c
drivers/media/video/cx231xx/cx231xx-vbi.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25821/cx25821-core.c
drivers/media/video/cx25821/cx25821.h
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/gspca/sn9c20x.c
drivers/media/video/mx2_camera.c
drivers/media/video/omap3isp/isppreview.c
drivers/media/video/pms.c
drivers/media/video/s5p-fimc/fimc-capture.c
drivers/media/video/s5p-fimc/fimc-core.c
drivers/media/video/s5p-fimc/fimc-lite.c
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-fimc/fimc-mdevice.h
drivers/media/video/s5p-mfc/s5p_mfc_dec.c
drivers/media/video/s5p-mfc/s5p_mfc_enc.c
drivers/media/video/smiapp/smiapp-core.c
drivers/media/video/v4l2-dev.c
drivers/media/video/zoran/zoran.h
drivers/media/video/zoran/zoran_driver.c
drivers/mfd/Kconfig
drivers/mfd/ab5500-core.h [deleted file]
drivers/mfd/mc13xxx-spi.c
drivers/mfd/omap-usb-host.c
drivers/mfd/palmas.c
drivers/mfd/tps65217.c
drivers/misc/mei/main.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/mmc/card/block.c
drivers/mmc/core/Makefile
drivers/mmc/core/cd-gpio.c [deleted file]
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_cis.c
drivers/mmc/core/slot-gpio.c [new file with mode: 0644]
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mtd/mtdsuper.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nandsim.c
drivers/mtd/ubi/Kconfig
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/vmt.c
drivers/net/bonding/bond_debugfs.c
drivers/net/bonding/bond_main.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/intel/e1000e/82571.c
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igbvf/ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/phy/mdio-mux.c
drivers/net/usb/qmi_wwan.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/key.c
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlwifi/iwl-mac80211.c
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/11n_rxreorder.h
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/ie.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/ti/wlcore/Kconfig
drivers/of/platform.c
drivers/oprofile/oprofile_perf.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/quirks.c
drivers/pinctrl/pinctrl-imx.c
drivers/pinctrl/pinctrl-imx6q.c
drivers/pinctrl/pinctrl-nomadik.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/fujitsu-tablet.c
drivers/platform/x86/hdaps.c
drivers/platform/x86/hp_accel.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_ips.c
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/toshiba_bluetooth.c
drivers/platform/x86/xo15-ebook.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/aat2870-regulator.c
drivers/regulator/ab3100.c
drivers/regulator/ab8500.c
drivers/regulator/ad5398.c
drivers/regulator/anatop-regulator.c
drivers/regulator/arizona-ldo1.c [new file with mode: 0644]
drivers/regulator/arizona-micsupp.c [new file with mode: 0644]
drivers/regulator/core.c
drivers/regulator/da903x.c
drivers/regulator/da9052-regulator.c
drivers/regulator/fixed-helper.c
drivers/regulator/fixed.c
drivers/regulator/gpio-regulator.c
drivers/regulator/isl6271a-regulator.c
drivers/regulator/lp3971.c
drivers/regulator/lp3972.c
drivers/regulator/lp872x.c [new file with mode: 0644]
drivers/regulator/lp8788-buck.c [new file with mode: 0644]
drivers/regulator/lp8788-ldo.c [new file with mode: 0644]
drivers/regulator/max1586.c
drivers/regulator/max77686.c [new file with mode: 0644]
drivers/regulator/max8952.c
drivers/regulator/max8997.c
drivers/regulator/max8998.c
drivers/regulator/mc13783-regulator.c
drivers/regulator/mc13892-regulator.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/mc13xxx.h
drivers/regulator/of_regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/pcap-regulator.c
drivers/regulator/pcf50633-regulator.c
drivers/regulator/rc5t583-regulator.c
drivers/regulator/s2mps11.c [new file with mode: 0644]
drivers/regulator/s5m8767.c
drivers/regulator/tps6105x-regulator.c
drivers/regulator/tps62360-regulator.c
drivers/regulator/tps65023-regulator.c
drivers/regulator/tps6507x-regulator.c
drivers/regulator/tps65217-regulator.c
drivers/regulator/tps6524x-regulator.c
drivers/regulator/tps6586x-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/regulator/twl-regulator.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8350-regulator.c
drivers/regulator/wm8400-regulator.c
drivers/regulator/wm8994-regulator.c
drivers/remoteproc/Kconfig
drivers/rpmsg/virtio_rpmsg_bus.c
drivers/rtc/rtc-ab8500.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-spear.c
drivers/rtc/rtc-stmp3xxx.c
drivers/rtc/rtc-twl.c
drivers/scsi/aic94xx/aic94xx_task.c
drivers/scsi/bnx2i/bnx2i.h
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/libsas/sas_ata.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_wait_scan.c
drivers/spi/spi-s3c64xx.c
drivers/target/Makefile
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_tmr.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/loopback/tcm_loop.c
drivers/target/sbp/sbp_target.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_iblock.h
drivers/target/target_core_internal.h
drivers/target/target_core_pr.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_rd.c
drivers/target/target_core_sbc.c [new file with mode: 0644]
drivers/target/target_core_spc.c [moved from drivers/target/target_core_cdb.c with 76% similarity]
drivers/target/target_core_tmr.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_io.c
drivers/target/tcm_fc/tfc_sess.c
drivers/tty/hvc/hvc_opal.c
drivers/tty/serial/mxs-auart.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/hub.c
drivers/usb/gadget/tcm_usb_gadget.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h
drivers/usb/serial/metro-usb.c
drivers/usb/serial/option.c
drivers/video/mxsfb.c
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/venc.c
drivers/virtio/virtio_balloon.c
drivers/watchdog/omap_wdt.c
fs/9p/v9fs.h
fs/9p/vfs_dentry.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/9p/vfs_super.c
fs/adfs/dir.c
fs/adfs/super.c
fs/affs/affs.h
fs/affs/amigaffs.c
fs/affs/bitmap.c
fs/affs/namei.c
fs/affs/super.c
fs/afs/dir.c
fs/afs/mntpt.c
fs/afs/super.c
fs/aio.c
fs/attr.c
fs/autofs4/dev-ioctl.c
fs/autofs4/root.c
fs/bad_inode.c
fs/befs/linuxvfs.c
fs/bfs/dir.c
fs/block_dev.c
fs/btrfs/backref.c
fs/btrfs/ctree.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ioctl.h
fs/btrfs/super.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/buffer.c
fs/cachefiles/namei.c
fs/cachefiles/rdwr.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/super.c
fs/ceph/super.h
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/cifs/transport.c
fs/coda/cache.c
fs/coda/dir.c
fs/configfs/dir.c
fs/cramfs/inode.c
fs/dcache.c
fs/debugfs/inode.c
fs/devpts/inode.c
fs/direct-io.c
fs/ecryptfs/dentry.c
fs/ecryptfs/ecryptfs_kernel.h
fs/ecryptfs/inode.c
fs/ecryptfs/kthread.c
fs/ecryptfs/main.c
fs/ecryptfs/miscdev.c
fs/efs/efs.h
fs/efs/namei.c
fs/eventpoll.c
fs/exofs/namei.c
fs/exofs/ore.c
fs/exofs/ore_raid.c
fs/exportfs/expfs.c
fs/ext2/namei.c
fs/ext2/super.c
fs/ext3/dir.c
fs/ext3/namei.c
fs/ext3/super.c
fs/ext4/dir.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/ioctl.c
fs/ext4/namei.c
fs/ext4/super.c
fs/fat/inode.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fifo.c
fs/file_table.c
fs/freevxfs/vxfs_lookup.c
fs/fs-writeback.c
fs/fs_struct.c
fs/fuse/dir.c
fs/gfs2/dentry.c
fs/gfs2/inode.c
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/quota.h
fs/gfs2/super.c
fs/gfs2/sys.c
fs/hfs/dir.c
fs/hfs/extent.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfs/mdb.c
fs/hfs/super.c
fs/hfs/sysdep.c
fs/hfsplus/bitmap.c
fs/hfsplus/dir.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hfsplus/super.c
fs/hostfs/hostfs_kern.c
fs/hpfs/dir.c
fs/hpfs/hpfs_fn.h
fs/hpfs/namei.c
fs/hppfs/hppfs.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/internal.h
fs/isofs/isofs.h
fs/isofs/namei.c
fs/jffs2/dir.c
fs/jfs/namei.c
fs/jfs/super.c
fs/libfs.c
fs/locks.c
fs/logfs/dir.c
fs/logfs/super.c
fs/minix/namei.c
fs/mount.h
fs/namei.c
fs/namespace.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/getroot.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/proc.c
fs/nfs/super.c
fs/nfsd/vfs.c
fs/nilfs2/namei.c
fs/nilfs2/super.c
fs/notify/fanotify/fanotify_user.c
fs/notify/fsnotify.c
fs/ntfs/namei.c
fs/ocfs2/dcache.c
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/dlmglue.c
fs/ocfs2/extent_map.c
fs/ocfs2/file.c
fs/ocfs2/namei.c
fs/ocfs2/quota_global.c
fs/omfs/dir.c
fs/open.c
fs/openpromfs/inode.c
fs/pnode.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/internal.h
fs/proc/namespaces.c
fs/proc/proc_net.c
fs/proc/proc_sysctl.c
fs/proc/root.c
fs/proc_namespace.c
fs/qnx4/namei.c
fs/qnx4/qnx4.h
fs/qnx6/inode.c
fs/qnx6/namei.c
fs/qnx6/qnx6.h
fs/quota/dquot.c
fs/quota/quota.c
fs/ramfs/file-nommu.c
fs/ramfs/inode.c
fs/read_write.c
fs/reiserfs/namei.c
fs/reiserfs/procfs.c
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/romfs/super.c
fs/splice.c
fs/squashfs/namei.c
fs/super.c
fs/sync.c
fs/sysfs/dir.c
fs/sysfs/mount.c
fs/sysfs/sysfs.h
fs/sysv/inode.c
fs/sysv/namei.c
fs/sysv/sysv.h
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/dir.c
fs/ubifs/orphan.c
fs/ubifs/replay.c
fs/ubifs/sb.c
fs/ubifs/super.c
fs/udf/namei.c
fs/ufs/balloc.c
fs/ufs/ialloc.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/ufs.h
fs/ufs/ufs_fs.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c
include/acpi/acpi_bus.h
include/acpi/processor.h
include/asm-generic/dma-contiguous.h
include/linux/aio.h
include/linux/blkdev.h
include/linux/bootmem.h
include/linux/capability.h
include/linux/ceph/messenger.h
include/linux/cpuidle.h
include/linux/dcache.h
include/linux/device.h
include/linux/eventpoll.h
include/linux/file.h
include/linux/fs.h
include/linux/ftrace_event.h
include/linux/gpio.h
include/linux/hrtimer.h
include/linux/i2c/twl.h
include/linux/init_task.h
include/linux/input.h
include/linux/intel-iommu.h
include/linux/irq.h
include/linux/jump_label.h
include/linux/kernel.h
include/linux/key.h
include/linux/kmsg_dump.h
include/linux/kvm_host.h
include/linux/memblock.h
include/linux/mfd/s5m87xx/s5m-core.h
include/linux/mfd/tmio.h
include/linux/mfd/tps65217.h
include/linux/mfd/tps65910.h
include/linux/mm.h
include/linux/mmc/card.h
include/linux/mmc/cd-gpio.h [deleted file]
include/linux/mmc/host.h
include/linux/mmc/sdhci.h
include/linux/mmc/sh_mmcif.h
include/linux/mmc/sh_mobile_sdhi.h
include/linux/mmc/slot-gpio.h [new file with mode: 0644]
include/linux/mmzone.h
include/linux/mxsfb.h [moved from arch/arm/mach-mxs/include/mach/mxsfb.h with 95% similarity]
include/linux/namei.h
include/linux/nfs_xdr.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/perf_event.h
include/linux/platform_data/clk-nomadik.h [new file with mode: 0644]
include/linux/pm_domain.h
include/linux/pm_qos.h
include/linux/prctl.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/rcupdate.h
include/linux/rcutiny.h
include/linux/regmap.h
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/regulator/fixed.h
include/linux/regulator/lp872x.h [new file with mode: 0644]
include/linux/regulator/machine.h
include/linux/rpmsg.h
include/linux/sched.h
include/linux/smp.h
include/linux/splice.h
include/linux/suspend.h
include/linux/task_work.h
include/linux/tick.h
include/linux/tracehook.h
include/linux/tracepoint.h
include/linux/types.h
include/net/ip_vs.h
include/net/netfilter/nf_conntrack_ecache.h
include/net/scm.h
include/net/sctp/structs.h
include/net/sctp/tsnmap.h
include/scsi/libsas.h
include/scsi/scsi_cmnd.h
include/target/target_core_backend.h
include/target/target_core_base.h
include/target/target_core_fabric.h
include/trace/events/rcu.h
include/trace/ftrace.h
init/main.c
ipc/mqueue.c
kernel/audit_tree.c
kernel/audit_watch.c
kernel/cgroup.c
kernel/debug/kdb/kdb_main.c
kernel/debug/kdb/kdb_private.h
kernel/events/core.c
kernel/events/uprobes.c
kernel/exit.c
kernel/fork.c
kernel/hrtimer.c
kernel/irq/manage.c
kernel/power/Kconfig
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/suspend.c
kernel/power/swap.c
kernel/power/user.c
kernel/power/wakelock.c
kernel/printk.c
kernel/rcupdate.c
kernel/rcutiny.c
kernel/rcutiny_plugin.h
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/rcutree_trace.c
kernel/relay.c
kernel/sched/core.c
kernel/sched/idle_task.c
kernel/sched/sched.h
kernel/signal.c
kernel/smp.c
kernel/smpboot.h
kernel/sys.c
kernel/task_work.c
kernel/time/ntp.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/time/timer_list.c
kernel/timer.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_functions_graph.c
kernel/trace/trace_output.c
lib/dma-debug.c
lib/list_debug.c
mm/bootmem.c
mm/compaction.c
mm/madvise.c
mm/memblock.c
mm/memory-failure.c
mm/memory_hotplug.c
mm/nobootmem.c
mm/page_alloc.c
mm/shmem.c
mm/sparse.c
mm/vmscan.c
net/8021q/vlan.c
net/ax25/af_ax25.c
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/bridge_loop_avoidance.h
net/batman-adv/soft-interface.c
net/caif/caif_dev.c
net/ceph/messenger.c
net/core/dev.c
net/core/net_namespace.c
net/core/netprio_cgroup.c
net/core/scm.c
net/core/skbuff.c
net/ieee802154/dgram.c
net/ipv4/cipso_ipv4.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nfnetlink.c
net/netfilter/xt_set.c
net/nfc/llcp/sock.c
net/nfc/nci/ntf.c
net/nfc/rawsock.c
net/rxrpc/ar-peer.c
net/sched/sch_netem.c
net/sched/sch_sfb.c
net/sctp/associola.c
net/sctp/input.c
net/sctp/output.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/transport.c
net/sctp/tsnmap.c
net/sctp/ulpevent.c
net/sctp/ulpqueue.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/process_keys.c
security/security.c
security/selinux/hooks.c
security/selinux/include/classmap.h
security/selinux/include/security.h
security/selinux/selinuxfs.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/wm2200.c
sound/soc/samsung/dma.c
sound/soc/tegra/Kconfig
sound/usb/endpoint.c
sound/usb/pcm.c
tools/lib/traceevent/Makefile
tools/lib/traceevent/event-parse.c
tools/lib/traceevent/event-parse.h
tools/lib/traceevent/parse-filter.c
tools/perf/Documentation/perf-bench.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile
tools/perf/bench/mem-memcpy.c
tools/perf/bench/mem-memset.c
tools/perf/builtin-bench.c
tools/perf/builtin-evlist.c
tools/perf/builtin-kmem.c
tools/perf/builtin-lock.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/config/feature-tests.mak
tools/perf/ui/browsers/annotate.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/browser.c
tools/perf/ui/gtk/gtk.h
tools/perf/ui/gtk/setup.c
tools/perf/ui/gtk/util.c [new file with mode: 0644]
tools/perf/ui/tui/setup.c
tools/perf/ui/tui/util.c [new file with mode: 0644]
tools/perf/ui/util.c
tools/perf/ui/util.h
tools/perf/util/debug.c
tools/perf/util/debug.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/hist.h
tools/perf/util/include/linux/kernel.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/parse-events-test.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.l
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/string.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/top.c
tools/perf/util/trace-event-parse.c
tools/perf/util/trace-event-read.c
tools/perf/util/trace-event-scripting.c
tools/perf/util/trace-event.h
tools/perf/util/util.h
virt/kvm/assigned-dev.c
virt/kvm/eventfd.c
virt/kvm/kvm_main.c

index 679ce354312281846e4ef2decee0689b0775c985..beef30c046b0d3181bfc353d15704bb4bdaf3da6 100644 (file)
@@ -1,26 +1,5 @@
-What:           /sys/block/rssd*/registers
-Date:           March 2012
-KernelVersion:  3.3
-Contact:        Asai Thambi S P <asamymuthupa@micron.com>
-Description:    This is a read-only file. Dumps below driver information and
-                hardware registers.
-                    - S ACTive
-                    - Command Issue
-                    - Completed
-                    - PORT IRQ STAT
-                    - HOST IRQ STAT
-                    - Allocated
-                    - Commands in Q
-
 What:           /sys/block/rssd*/status
 Date:           April 2012
 KernelVersion:  3.4
 Contact:        Asai Thambi S P <asamymuthupa@micron.com>
 Description:    This is a read-only file. Indicates the status of the device.
-
-What:           /sys/block/rssd*/flags
-Date:           May 2012
-KernelVersion:  3.5
-Contact:        Asai Thambi S P <asamymuthupa@micron.com>
-Description:    This is a read-only file. Dumps the flags in port and driver
-                data structure
index db1ad7e34fc3a00e14be0c1045564fe6c98bd37e..938ef71e2035e7c04203c7b65d2a120dbd96944a 100644 (file)
@@ -142,13 +142,14 @@ KernelVersion:    3.4
 Contact:       linux-mtd@lists.infradead.org
 Description:
                This allows the user to examine and adjust the criteria by which
-               mtd returns -EUCLEAN from mtd_read().  If the maximum number of
-               bit errors that were corrected on any single region comprising
-               an ecc step (as reported by the driver) equals or exceeds this
-               value, -EUCLEAN is returned.  Otherwise, absent an error, 0 is
-               returned.  Higher layers (e.g., UBI) use this return code as an
-               indication that an erase block may be degrading and should be
-               scrutinized as a candidate for being marked as bad.
+               mtd returns -EUCLEAN from mtd_read() and mtd_read_oob().  If the
+               maximum number of bit errors that were corrected on any single
+               region comprising an ecc step (as reported by the driver) equals
+               or exceeds this value, -EUCLEAN is returned.  Otherwise, absent
+               an error, 0 is returned.  Higher layers (e.g., UBI) use this
+               return code as an indication that an erase block may be
+               degrading and should be scrutinized as a candidate for being
+               marked as bad.
 
                The initial value may be specified by the flash device driver.
                If not, then the default value is ecc_strength.
@@ -167,7 +168,7 @@ Description:
                block degradation, but high enough to avoid the consequences of
                a persistent return value of -EUCLEAN on devices where sticky
                bitflips occur.  Note that if bitflip_threshold exceeds
-               ecc_strength, -EUCLEAN is never returned by mtd_read().
+               ecc_strength, -EUCLEAN is never returned by the read operations.
                Conversely, if bitflip_threshold is zero, -EUCLEAN is always
                returned, absent a hard error.
 
index 31725ffeeb3a3bc09bb4c712a3f88bfbe941aae8..217772615d0288f996e05cc128b98c9a40d95042 100644 (file)
@@ -231,3 +231,16 @@ Description:
                Reads from this file return a string consisting of the names of
                wakeup sources created with the help of /sys/power/wake_lock
                that are inactive at the moment, separated with spaces.
+
+What:          /sys/power/pm_print_times
+Date:          May 2012
+Contact:       Sameer Nanda <snanda@chromium.org>
+Description:
+               The /sys/power/pm_print_times file allows user space to
+               control whether the time taken by devices to suspend and
+               resume is printed.  These prints are useful for hunting down
+               devices that take too long to suspend or resume.
+
+               Writing a "1" enables this printing while writing a "0"
+               disables it.  The default value is "0".  Reading from this file
+               will display the current value.
index 676bc46f9c52a476b3c8c280cca437d756726235..cda0dfb6769aee5d0fcadb8a30b4d19658259bc7 100644 (file)
@@ -3988,7 +3988,7 @@ interface and may change in the future.</para>
            from RGB to Y'CbCr color space.
            </entry>
          </row>
-         <row id = "v4l2-jpeg-chroma-subsampling">
+         <row>
            <entrytbl spanname="descr" cols="2">
              <tbody valign="top">
                <row>
index e3d5afcdafbb5b03cf9994478e3e0d8139442dda..0a4b90fcf2dab77b36ed1e52749040ddcc97a113 100644 (file)
@@ -284,13 +284,6 @@ These controls are described in <xref
            processing controls. These controls are described in <xref
            linkend="image-process-controls" />.</entry>
          </row>
-         <row>
-           <entry><constant>V4L2_CTRL_CLASS_JPEG</constant></entry>
-           <entry>0x9d0000</entry>
-           <entry>The class containing JPEG compression controls.
-These controls are described in <xref
-               linkend="jpeg-controls" />.</entry>
-         </row>
        </tbody>
       </tgroup>
     </table>
index 5c8d74968090544ae570105b00a96561ea4acd6c..fc103d7a04740d338bf0490a2133674c25986d59 100644 (file)
@@ -162,9 +162,9 @@ over a rather long period of time, but improvements are always welcome!
                when publicizing a pointer to a structure that can
                be traversed by an RCU read-side critical section.
 
-5.     If call_rcu(), or a related primitive such as call_rcu_bh() or
-       call_rcu_sched(), is used, the callback function must be
-       written to be called from softirq context.  In particular,
+5.     If call_rcu(), or a related primitive such as call_rcu_bh(),
+       call_rcu_sched(), or call_srcu() is used, the callback function
+       must be written to be called from softirq context.  In particular,
        it cannot block.
 
 6.     Since synchronize_rcu() can block, it cannot be called from
@@ -202,11 +202,12 @@ over a rather long period of time, but improvements are always welcome!
        updater uses call_rcu_sched() or synchronize_sched(), then
        the corresponding readers must disable preemption, possibly
        by calling rcu_read_lock_sched() and rcu_read_unlock_sched().
-       If the updater uses synchronize_srcu(), the the corresponding
-       readers must use srcu_read_lock() and srcu_read_unlock(),
-       and with the same srcu_struct.  The rules for the expedited
-       primitives are the same as for their non-expedited counterparts.
-       Mixing things up will result in confusion and broken kernels.
+       If the updater uses synchronize_srcu() or call_srcu(),
+       the the corresponding readers must use srcu_read_lock() and
+       srcu_read_unlock(), and with the same srcu_struct.  The rules for
+       the expedited primitives are the same as for their non-expedited
+       counterparts.  Mixing things up will result in confusion and
+       broken kernels.
 
        One exception to this rule: rcu_read_lock() and rcu_read_unlock()
        may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh()
@@ -333,14 +334,14 @@ over a rather long period of time, but improvements are always welcome!
        victim CPU from ever going offline.)
 
 14.    SRCU (srcu_read_lock(), srcu_read_unlock(), srcu_dereference(),
-       synchronize_srcu(), and synchronize_srcu_expedited()) may only
-       be invoked from process context.  Unlike other forms of RCU, it
-       -is- permissible to block in an SRCU read-side critical section
-       (demarked by srcu_read_lock() and srcu_read_unlock()), hence the
-       "SRCU": "sleepable RCU".  Please note that if you don't need
-       to sleep in read-side critical sections, you should be using
-       RCU rather than SRCU, because RCU is almost always faster and
-       easier to use than is SRCU.
+       synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu())
+       may only be invoked from process context.  Unlike other forms of
+       RCU, it -is- permissible to block in an SRCU read-side critical
+       section (demarked by srcu_read_lock() and srcu_read_unlock()),
+       hence the "SRCU": "sleepable RCU".  Please note that if you
+       don't need to sleep in read-side critical sections, you should be
+       using RCU rather than SRCU, because RCU is almost always faster
+       and easier to use than is SRCU.
 
        If you need to enter your read-side critical section in a
        hardirq or exception handler, and then exit that same read-side
@@ -353,8 +354,8 @@ over a rather long period of time, but improvements are always welcome!
        cleanup_srcu_struct().  These are passed a "struct srcu_struct"
        that defines the scope of a given SRCU domain.  Once initialized,
        the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
-       synchronize_srcu(), and synchronize_srcu_expedited().  A given
-       synchronize_srcu() waits only for SRCU read-side critical
+       synchronize_srcu(), synchronize_srcu_expedited(), and call_srcu().
+       A given synchronize_srcu() waits only for SRCU read-side critical
        sections governed by srcu_read_lock() and srcu_read_unlock()
        calls that have been passed the same srcu_struct.  This property
        is what makes sleeping read-side critical sections tolerable --
@@ -374,7 +375,7 @@ over a rather long period of time, but improvements are always welcome!
        requiring SRCU's read-side deadlock immunity or low read-side
        realtime latency.
 
-       Note that, rcu_assign_pointer() relates to SRCU just as they do
+       Note that, rcu_assign_pointer() relates to SRCU just as it does
        to other forms of RCU.
 
 15.    The whole point of call_rcu(), synchronize_rcu(), and friends
index e439a0edee2263d554a53282aaa8512b0295a40c..38428c125135504de8737943088a4e0f3df6f213 100644 (file)
@@ -79,8 +79,6 @@ complete. Pseudo-code using rcu_barrier() is as follows:
    2. Execute rcu_barrier().
    3. Allow the module to be unloaded.
 
-Quick Quiz #1: Why is there no srcu_barrier()?
-
 The rcutorture module makes use of rcu_barrier in its exit function
 as follows:
 
@@ -162,7 +160,7 @@ for any pre-existing callbacks to complete.
 Then lines 55-62 print status and do operation-specific cleanup, and
 then return, permitting the module-unload operation to be completed.
 
-Quick Quiz #2: Is there any other situation where rcu_barrier() might
+Quick Quiz #1: Is there any other situation where rcu_barrier() might
        be required?
 
 Your module might have additional complications. For example, if your
@@ -242,7 +240,7 @@ reaches zero, as follows:
  4 complete(&rcu_barrier_completion);
  5 }
 
-Quick Quiz #3: What happens if CPU 0's rcu_barrier_func() executes
+Quick Quiz #2: What happens if CPU 0's rcu_barrier_func() executes
        immediately (thus incrementing rcu_barrier_cpu_count to the
        value one), but the other CPU's rcu_barrier_func() invocations
        are delayed for a full grace period? Couldn't this result in
@@ -259,12 +257,7 @@ so that your module may be safely unloaded.
 
 Answers to Quick Quizzes
 
-Quick Quiz #1: Why is there no srcu_barrier()?
-
-Answer: Since there is no call_srcu(), there can be no outstanding SRCU
-       callbacks. Therefore, there is no need to wait for them.
-
-Quick Quiz #2: Is there any other situation where rcu_barrier() might
+Quick Quiz #1: Is there any other situation where rcu_barrier() might
        be required?
 
 Answer: Interestingly enough, rcu_barrier() was not originally
@@ -278,7 +271,7 @@ Answer: Interestingly enough, rcu_barrier() was not originally
        implementing rcutorture, and found that rcu_barrier() solves
        this problem as well.
 
-Quick Quiz #3: What happens if CPU 0's rcu_barrier_func() executes
+Quick Quiz #2: What happens if CPU 0's rcu_barrier_func() executes
        immediately (thus incrementing rcu_barrier_cpu_count to the
        value one), but the other CPU's rcu_barrier_func() invocations
        are delayed for a full grace period? Couldn't this result in
index 4ddf3913fd8c0df7b91d2d29b17e3c69327907c7..7dce8a17eac269cdff475a57377bf49963c1216a 100644 (file)
@@ -174,11 +174,20 @@ torture_type      The type of RCU to test, with string values as follows:
                        and synchronize_rcu_bh_expedited().
 
                "srcu": srcu_read_lock(), srcu_read_unlock() and
+                       call_srcu().
+
+               "srcu_sync": srcu_read_lock(), srcu_read_unlock() and
                        synchronize_srcu().
 
                "srcu_expedited": srcu_read_lock(), srcu_read_unlock() and
                        synchronize_srcu_expedited().
 
+               "srcu_raw": srcu_read_lock_raw(), srcu_read_unlock_raw(),
+                       and call_srcu().
+
+               "srcu_raw_sync": srcu_read_lock_raw(), srcu_read_unlock_raw(),
+                       and synchronize_srcu().
+
                "sched": preempt_disable(), preempt_enable(), and
                        call_rcu_sched().
 
index 6bbe8dcdc3da94166160f3d27a96a6f2a622287f..69ee188515e7a9c907ec243dfff21852e55a9998 100644 (file)
@@ -833,9 +833,9 @@ sched:      Critical sections       Grace period            Barrier
 
 SRCU:  Critical sections       Grace period            Barrier
 
-       srcu_read_lock          synchronize_srcu        N/A
-       srcu_read_unlock        synchronize_srcu_expedited
-       srcu_read_lock_raw
+       srcu_read_lock          synchronize_srcu        srcu_barrier
+       srcu_read_unlock        call_srcu
+       srcu_read_lock_raw      synchronize_srcu_expedited
        srcu_read_unlock_raw
        srcu_dereference
 
index 32e48797a14f80de6ebff7a441e489021bfce58a..9884681535ee36bf03a7d7baaa54abb36360d53d 100644 (file)
@@ -7,39 +7,39 @@ This target is read-only.
 
 Construction Parameters
 =======================
-    <version> <dev> <hash_dev> <hash_start>
+    <version> <dev> <hash_dev>
     <data_block_size> <hash_block_size>
     <num_data_blocks> <hash_start_block>
     <algorithm> <digest> <salt>
 
 <version>
-    This is the version number of the on-disk format.
+    This is the type of the on-disk hash format.
 
     0 is the original format used in the Chromium OS.
-       The salt is appended when hashing, digests are stored continuously and
-       the rest of the block is padded with zeros.
+      The salt is appended when hashing, digests are stored continuously and
+      the rest of the block is padded with zeros.
 
     1 is the current format that should be used for new devices.
-       The salt is prepended when hashing and each digest is
-       padded with zeros to the power of two.
+      The salt is prepended when hashing and each digest is
+      padded with zeros to the power of two.
 
 <dev>
-    This is the device containing the data the integrity of which needs to be
+    This is the device containing data, the integrity of which needs to be
     checked.  It may be specified as a path, like /dev/sdaX, or a device number,
     <major>:<minor>.
 
 <hash_dev>
-    This is the device that that supplies the hash tree data.  It may be
+    This is the device that supplies the hash tree data.  It may be
     specified similarly to the device path and may be the same device.  If the
-    same device is used, the hash_start should be outside of the dm-verity
-    configured device size.
+    same device is used, the hash_start should be outside the configured
+    dm-verity device.
 
 <data_block_size>
-    The block size on a data device.  Each block corresponds to one digest on
-    the hash device.
+    The block size on a data device in bytes.
+    Each block corresponds to one digest on the hash device.
 
 <hash_block_size>
-    The size of a hash block.
+    The size of a hash block in bytes.
 
 <num_data_blocks>
     The number of data blocks on the data device.  Additional blocks are
@@ -65,7 +65,7 @@ Construction Parameters
 Theory of operation
 ===================
 
-dm-verity is meant to be setup as part of a verified boot path.  This
+dm-verity is meant to be set up as part of a verified boot path.  This
 may be anything ranging from a boot using tboot or trustedgrub to just
 booting from a known-good device (like a USB drive or CD).
 
@@ -73,20 +73,20 @@ When a dm-verity device is configured, it is expected that the caller
 has been authenticated in some way (cryptographic signatures, etc).
 After instantiation, all hashes will be verified on-demand during
 disk access.  If they cannot be verified up to the root node of the
-tree, the root hash, then the I/O will fail.  This should identify
+tree, the root hash, then the I/O will fail.  This should detect
 tampering with any data on the device and the hash data.
 
 Cryptographic hashes are used to assert the integrity of the device on a
-per-block basis.  This allows for a lightweight hash computation on first read
-into the page cache.  Block hashes are stored linearly-aligned to the nearest
-block the size of a page.
+per-block basis. This allows for a lightweight hash computation on first read
+into the page cache. Block hashes are stored linearly, aligned to the nearest
+block size.
 
 Hash Tree
 ---------
 
 Each node in the tree is a cryptographic hash.  If it is a leaf node, the hash
-is of some block data on disk.  If it is an intermediary node, then the hash is
-of a number of child nodes.
+of some data block on disk is calculated. If it is an intermediary node,
+the hash of a number of child nodes is calculated.
 
 Each entry in the tree is a collection of neighboring nodes that fit in one
 block.  The number is determined based on block_size and the size of the
@@ -110,63 +110,23 @@ alg = sha256, num_blocks = 32768, block_size = 4096
 On-disk format
 ==============
 
-Below is the recommended on-disk format. The verity kernel code does not
-read the on-disk header. It only reads the hash blocks which directly
-follow the header. It is expected that a user-space tool will verify the
-integrity of the verity_header and then call dmsetup with the correct
-parameters. Alternatively, the header can be omitted and the dmsetup
-parameters can be passed via the kernel command-line in a rooted chain
-of trust where the command-line is verified.
+The verity kernel code does not read the verity metadata on-disk header.
+It only reads the hash blocks which directly follow the header.
+It is expected that a user-space tool will verify the integrity of the
+verity header.
 
-The on-disk format is especially useful in cases where the hash blocks
-are on a separate partition. The magic number allows easy identification
-of the partition contents. Alternatively, the hash blocks can be stored
-in the same partition as the data to be verified. In such a configuration
-the filesystem on the partition would be sized a little smaller than
-the full-partition, leaving room for the hash blocks.
-
-struct superblock {
-       uint8_t signature[8]
-               "verity\0\0";
-
-       uint8_t version;
-               1 - current format
-
-       uint8_t data_block_bits;
-               log2(data block size)
-
-       uint8_t hash_block_bits;
-               log2(hash block size)
-
-       uint8_t pad1[1];
-               zero padding
-
-       uint16_t salt_size;
-               big-endian salt size
-
-       uint8_t pad2[2];
-               zero padding
-
-       uint32_t data_blocks_hi;
-               big-endian high 32 bits of the 64-bit number of data blocks
-
-       uint32_t data_blocks_lo;
-               big-endian low 32 bits of the 64-bit number of data blocks
-
-       uint8_t algorithm[16];
-               cryptographic algorithm
-
-       uint8_t salt[384];
-               salt (the salt size is specified above)
-
-       uint8_t pad3[88];
-               zero padding to 512-byte boundary
-}
+Alternatively, the header can be omitted and the dmsetup parameters can
+be passed via the kernel command-line in a rooted chain of trust where
+the command-line is verified.
 
 Directly following the header (and with sector number padded to the next hash
 block boundary) are the hash blocks which are stored a depth at a time
 (starting from the root), sorted in order of increasing index.
 
+The full specification of kernel parameters and on-disk metadata format
+is available at the cryptsetup project's wiki page
+  http://code.google.com/p/cryptsetup/wiki/DMVerity
+
 Status
 ======
 V (for Valid) is returned if every check performed so far was valid.
@@ -174,21 +134,22 @@ If any check failed, C (for Corruption) is returned.
 
 Example
 =======
-
-Setup a device:
-  dmsetup create vroot --table \
-    "0 2097152 "\
-    "verity 1 /dev/sda1 /dev/sda2 4096 4096 2097152 1 "\
+Set up a device:
+  # dmsetup create vroot --readonly --table \
+    "0 2097152 verity 1 /dev/sda1 /dev/sda2 4096 4096 262144 1 sha256 "\
     "4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
     "1234000000000000000000000000000000000000000000000000000000000000"
 
 A command line tool veritysetup is available to compute or verify
-the hash tree or activate the kernel driver.  This is available from
-the LVM2 upstream repository and may be supplied as a package called
-device-mapper-verity-tools:
-    git://sources.redhat.com/git/lvm2
-    http://sourceware.org/git/?p=lvm2.git
-    http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity?cvsroot=lvm2
-
-veritysetup -a vroot /dev/sda1 /dev/sda2 \
-       4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
+the hash tree or activate the kernel device. This is available from
+the cryptsetup upstream repository http://code.google.com/p/cryptsetup/
+(as a libcryptsetup extension).
+
+Create hash on the device:
+  # veritysetup format /dev/sda1 /dev/sda2
+  ...
+  Root hash: 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
+
+Activate the device:
+  # veritysetup create vroot /dev/sda1 /dev/sda2 \
+    4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076
index aabca4f83402198c50893724a2d3dbcfb3d221d4..19078bf5cca82b22e5aba7882d592242d924fd48 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 - compatible: Should be "atmel,<chip>-aic"
 - interrupt-controller: Identifies the node as an interrupt controller.
 - interrupt-parent: For single AIC system, it is an empty property.
-- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
+- #interrupt-cells: The number of cells to define the interrupts. It sould be 3.
   The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
   The second cell is used to specify flags:
     bits[3:0] trigger type and level flags:
@@ -14,7 +14,10 @@ Required properties:
       8 = active low level-sensitive.
       Valid combinations are 1, 2, 3, 4, 8.
       Default flag for internal sources should be set to 4 (active high).
+  The third cell is used to specify the irq priority from 0 (lowest) to 7
+  (highest).
 - reg: Should contain AIC registers location and length
+- atmel,external-irqs: u32 array of external irqs.
 
 Examples:
        /*
@@ -24,7 +27,7 @@ Examples:
                compatible = "atmel,at91rm9200-aic";
                interrupt-controller;
                interrupt-parent;
-               #interrupt-cells = <2>;
+               #interrupt-cells = <3>;
                reg = <0xfffff000 0x200>;
        };
 
@@ -34,5 +37,5 @@ Examples:
        dma: dma-controller@ffffec00 {
                compatible = "atmel,at91sam9g45-dma";
                reg = <0xffffec00 0x200>;
-               interrupts = <21 4>;
+               interrupts = <21 4 5>;
        };
diff --git a/Documentation/devicetree/bindings/arm/davinci/cp-intc.txt b/Documentation/devicetree/bindings/arm/davinci/cp-intc.txt
new file mode 100644 (file)
index 0000000..597e8a0
--- /dev/null
@@ -0,0 +1,27 @@
+* TI Common Platform Interrupt Controller
+
+Common Platform Interrupt Controller (cp_intc) is used on
+OMAP-L1x SoCs and can support several configurable number
+of interrupts.
+
+Main node required properties:
+
+- compatible : should be:
+       "ti,cp-intc"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The type shall be a <u32> and the value shall be 1.
+
+  The cell contains the interrupt number in the range [0-128].
+- ti,intc-size: Number of interrupts handled by the interrupt controller.
+- reg: physical base address and size of the intc registers map.
+
+Example:
+
+       intc: interrupt-controller@1 {
+               compatible = "ti,cp-intc";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               ti,intc-size = <101>;
+               reg = <0xfffee000 0x2000>;
+       };
diff --git a/Documentation/devicetree/bindings/arm/olimex.txt b/Documentation/devicetree/bindings/arm/olimex.txt
new file mode 100644 (file)
index 0000000..007fb5c
--- /dev/null
@@ -0,0 +1,6 @@
+Olimex i.MX Platforms Device Tree Bindings
+------------------------------------------
+
+i.MX23 Olinuxino Low Cost Board
+Required root node properties:
+    - compatible = "olimex,imx23-olinuxino", "fsl,imx23";
index 3d450f65a17bdc2a6c4e71beb826bf1a65ed44f8..ccdd0e53451fc916cd0bfe020fab31ccf52af84d 100644 (file)
@@ -48,5 +48,8 @@ Boards:
 - AM335X EVM : Software Developement Board for AM335x
   compatible = "ti,am335x-evm", "ti,am33xx", "ti,omap3"
 
+- AM335X Bone : Low cost community board
+  compatible = "ti,am335x-bone", "ti,am33xx", "ti,omap3"
+
 - OMAP5 EVM : Evaluation Module
   compatible = "ti,omap5-evm", "ti,omap5"
similarity index 99%
rename from Documentation/devicetree/bindings/arm/tegra/emc.txt
rename to Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt
index 09335f8eee0068c091546fb82d66b506c61701b5..4c33b29dc66070abe48bfb0f47d3f01aa9c81773 100644 (file)
@@ -15,7 +15,7 @@ Child device nodes describe the memory settings for different configurations and
 
 Example:
 
-       emc@7000f400 {
+       memory-controller@7000f400 {
                #address-cells = < 1 >;
                #size-cells = < 0 >;
                compatible = "nvidia,tegra20-emc";
index c25a0a55151d900b612ffbe518d3605642cce5ac..866d93421eba20ba81fa66e905ecd58213636d95 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
 - interrupts : Should contain MC General interrupt.
 
 Example:
-       mc {
+       memory-controller@0x7000f000 {
                compatible = "nvidia,tegra20-mc";
                reg = <0x7000f000 0x024
                       0x7000f03c 0x3c4>;
index e47e73f612f4b30e5cb47a2ee4736db84bf9ef9f..bdf1a612422bcb004a4c262648c422ec22fa9ea8 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
 - interrupts : Should contain MC General interrupt.
 
 Example:
-       mc {
+       memory-controller {
                compatible = "nvidia,tegra30-mc";
                reg = <0x7000f000 0x010
                       0x7000f03c 0x1b4
diff --git a/Documentation/devicetree/bindings/fb/mxsfb.txt b/Documentation/devicetree/bindings/fb/mxsfb.txt
new file mode 100644 (file)
index 0000000..b41e5e5
--- /dev/null
@@ -0,0 +1,19 @@
+* Freescale MXS LCD Interface (LCDIF)
+
+Required properties:
+- compatible: Should be "fsl,<chip>-lcdif".  Supported chips include
+  imx23 and imx28.
+- reg: Address and length of the register set for lcdif
+- interrupts: Should contain lcdif interrupts
+
+Optional properties:
+- panel-enable-gpios : Should specify the gpio for panel enable
+
+Examples:
+
+lcdif@80030000 {
+       compatible = "fsl,imx28-lcdif";
+       reg = <0x80030000 2000>;
+       interrupts = <38 86>;
+       panel-enable-gpios = <&gpio3 30 0>;
+};
index 4363ae4b3c14741008b4d1e61db4b90a161ff0cc..4f3929713ae4d16df7f5f55dbb70459a8df02c76 100644 (file)
@@ -8,8 +8,16 @@ Required properties:
   by low 16 pins and the second one is for high 16 pins.
 - gpio-controller : Marks the device node as a gpio controller.
 - #gpio-cells : Should be two.  The first cell is the pin number and
-  the second cell is used to specify optional parameters (currently
-  unused).
+  the second cell is used to specify the gpio polarity:
+      0 = active high
+      1 = active low
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells : Should be 2.  The first cell is the GPIO number.
+  The second cell bits[3:0] is used to specify trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
 
 Example:
 
@@ -19,4 +27,6 @@ gpio0: gpio@73f84000 {
        interrupts = <50 51>;
        gpio-controller;
        #gpio-cells = <2>;
+       interrupt-controller;
+       #interrupt-cells = <2>;
 };
index 0c35673f7a3ec16b8415ae1d8f2afa3abfbf3be2..1e677a47b83605ade43d6072711fa19b88e8a33f 100644 (file)
@@ -13,8 +13,9 @@ Required properties for GPIO node:
 - interrupts : Should be the port interrupt shared by all 32 pins.
 - gpio-controller : Marks the device node as a gpio controller.
 - #gpio-cells : Should be two.  The first cell is the pin number and
-  the second cell is used to specify optional parameters (currently
-  unused).
+  the second cell is used to specify the gpio polarity:
+      0 = active high
+      1 = active low
 - interrupt-controller: Marks the device node as an interrupt controller.
 - #interrupt-cells : Should be 2.  The first cell is the GPIO number.
   The second cell bits[3:0] is used to specify trigger type and level flags:
index ee87467ad8d684d33d43cbd1de95ed85699f3359..8315ac7780ef96429dd4b4dc421aa8ba98558081 100644 (file)
@@ -26,6 +26,6 @@ Example:
                         #gpio-cells = <2>;
                         gpio-controller;
                         interrupt-controller;
-                        supports-sleepmode;
+                        st,supports-sleepmode;
                         gpio-bank = <1>;
                 };
index a00c94ccbdeeb871c440b770de814d11c6f757d7..0b96e5737d3a569ca4acfec137cc6870d1b56880 100644 (file)
@@ -2,6 +2,7 @@
 
 Required properties:
 - compatible : "fsl,mma8450".
+- reg: the I2C address of MMA8450
 
 Example:
 
index 19f6af47a792986c23a9ed033e15e8639ec5c51b..baf07987ae6863c68b39efa5ba1227a327009337 100644 (file)
@@ -46,8 +46,8 @@ Examples:
 
 ecspi@70010000 { /* ECSPI1 */
        fsl,spi-num-chipselects = <2>;
-       cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
-                  <&gpio3 25 0>; /* GPIO4_25 */
+       cs-gpios = <&gpio4 24 0>, /* GPIO4_24 */
+                  <&gpio4 25 0>; /* GPIO4_25 */
        status = "okay";
 
        pmic: mc13892@0 {
index 645f5eaadb3f07dba8550f5a41acbc5f02899362..d2802d4717bcfe70c146c95a1bc430807feae514 100644 (file)
@@ -17,18 +17,46 @@ Required properties:
   device need to be present. The definition for each of these nodes is defined
   using the standard binding for regulators found at
   Documentation/devicetree/bindings/regulator/regulator.txt.
+  The regulator is matched with the regulator-compatible.
 
-  The valid names for regulators are:
+  The valid regulator-compatible values are:
   tps65910: vrtc, vio, vdd1, vdd2, vdd3, vdig1, vdig2, vpll, vdac, vaux1,
             vaux2, vaux33, vmmc
   tps65911: vrtc, vio, vdd1, vdd3, vddctrl, ldo1, ldo2, ldo3, ldo4, ldo5,
             ldo6, ldo7, ldo8
 
+- xxx-supply: Input voltage supply regulator.
+  These entries are require if regulators are enabled for a device. Missing of these
+  properties can cause the regulator registration fails.
+  If some of input supply is powered through battery or always-on supply then
+  also it is require to have these parameters with proper node handle of always
+  on power supply.
+  tps65910:
+       vcc1-supply: VDD1 input.
+       vcc2-supply: VDD2 input.
+       vcc3-supply: VAUX33 and VMMC input.
+       vcc4-supply: VAUX1 and VAUX2 input.
+       vcc5-supply: VPLL and VDAC input.
+       vcc6-supply: VDIG1 and VDIG2 input.
+       vcc7-supply: VRTC input.
+       vccio-supply: VIO input.
+  tps65911:
+       vcc1-supply: VDD1 input.
+       vcc2-supply: VDD2 input.
+       vcc3-supply: LDO6, LDO7 and LDO8 input.
+       vcc4-supply: LDO5 input.
+       vcc5-supply: LDO3 and LDO4 input.
+       vcc6-supply: LDO1 and LDO2 input.
+       vcc7-supply: VRTC input.
+       vccio-supply: VIO input.
+
 Optional properties:
 - ti,vmbch-threshold: (tps65911) main battery charged threshold
   comparator. (see VMBCH_VSEL in TPS65910 datasheet)
 - ti,vmbch2-threshold: (tps65911) main battery discharged threshold
   comparator. (see VMBCH_VSEL in TPS65910 datasheet)
+- ti,en-ck32k-xtal: enable external 32-kHz crystal oscillator (see CK32K_CTRL
+  in TPS6591X datasheet)
 - ti,en-gpio-sleep: enable sleep control for gpios
   There should be 9 entries here, one for each gpio.
 
@@ -56,74 +84,110 @@ Example:
 
                ti,en-gpio-sleep = <0 0 1 0 0 0 0 0 0>;
 
+               vcc1-supply = <&reg_parent>;
+               vcc2-supply = <&some_reg>;
+               vcc3-supply = <...>;
+               vcc4-supply = <...>;
+               vcc5-supply = <...>;
+               vcc6-supply = <...>;
+               vcc7-supply = <...>;
+               vccio-supply = <...>;
+
                regulators {
-                       vdd1_reg: vdd1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       vdd1_reg: regulator@0 {
+                               regulator-compatible = "vdd1";
+                               reg = <0>;
                                regulator-min-microvolt = < 600000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                                regulator-boot-on;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       vdd2_reg: vdd2 {
+                       vdd2_reg: regulator@1 {
+                               regulator-compatible = "vdd2";
+                               reg = <1>;
                                regulator-min-microvolt = < 600000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                                regulator-boot-on;
                                ti,regulator-ext-sleep-control = <4>;
                        };
-                       vddctrl_reg: vddctrl {
+                       vddctrl_reg: regulator@2 {
+                               regulator-compatible = "vddctrl";
+                               reg = <2>;
                                regulator-min-microvolt = < 600000>;
                                regulator-max-microvolt = <1400000>;
                                regulator-always-on;
                                regulator-boot-on;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       vio_reg: vio {
+                       vio_reg: regulator@3 {
+                               regulator-compatible = "vio";
+                               reg = <3>;
                                regulator-min-microvolt = <1500000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-always-on;
                                regulator-boot-on;
                                ti,regulator-ext-sleep-control = <1>;
                        };
-                       ldo1_reg: ldo1 {
+                       ldo1_reg: regulator@4 {
+                               regulator-compatible = "ldo1";
+                               reg = <4>;
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <3300000>;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       ldo2_reg: ldo2 {
+                       ldo2_reg: regulator@5 {
+                               regulator-compatible = "ldo2";
+                               reg = <5>;
                                regulator-min-microvolt = <1050000>;
                                regulator-max-microvolt = <1050000>;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       ldo3_reg: ldo3 {
+                       ldo3_reg: regulator@6 {
+                               regulator-compatible = "ldo3";
+                               reg = <6>;
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <3300000>;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       ldo4_reg: ldo4 {
+                       ldo4_reg: regulator@7 {
+                               regulator-compatible = "ldo4";
+                               reg = <7>;
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       ldo5_reg: ldo5 {
+                       ldo5_reg: regulator@8 {
+                               regulator-compatible = "ldo5";
+                               reg = <8>;
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <3300000>;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       ldo6_reg: ldo6 {
+                       ldo6_reg: regulator@9 {
+                               regulator-compatible = "ldo6";
+                               reg = <9>;
                                regulator-min-microvolt = <1200000>;
                                regulator-max-microvolt = <1200000>;
                                ti,regulator-ext-sleep-control = <0>;
                        };
-                       ldo7_reg: ldo7 {
+                       ldo7_reg: regulator@10 {
+                               regulator-compatible = "ldo7";
+                               reg = <10>;
                                regulator-min-microvolt = <1200000>;
                                regulator-max-microvolt = <1200000>;
                                regulator-always-on;
                                regulator-boot-on;
                                ti,regulator-ext-sleep-control = <1>;
                        };
-                       ldo8_reg: ldo8 {
+                       ldo8_reg: regulator@11 {
+                               regulator-compatible = "ldo8";
+                               reg = <11>;
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
index 0d93b4b0e0e3733f77d0b668f166f2a3ba983555..bd9be0b5bc2034279d628f07eece8a3d9c2b394d 100644 (file)
@@ -3,21 +3,22 @@
 The Enhanced Secure Digital Host Controller provides an interface
 for MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the sdhci-esdhc driver.
+
 Required properties:
-  - compatible : should be
-    "fsl,<chip>-esdhc", "fsl,esdhc"
-  - reg : should contain eSDHC registers location and length.
-  - interrupts : should contain eSDHC interrupt.
   - interrupt-parent : interrupt source phandle.
   - clock-frequency : specifies eSDHC base clock frequency.
-  - sdhci,wp-inverted : (optional) specifies that eSDHC controller
-    reports inverted write-protect state; New devices should use
-    the generic "wp-inverted" property.
-  - sdhci,1-bit-only : (optional) specifies that a controller can
-    only handle 1-bit data transfers. New devices should use the
-    generic "bus-width = <1>" property.
-  - sdhci,auto-cmd12: (optional) specifies that a controller can
-    only handle auto CMD12.
+
+Optional properties:
+  - sdhci,wp-inverted : specifies that eSDHC controller reports
+    inverted write-protect state; New devices should use the generic
+    "wp-inverted" property.
+  - sdhci,1-bit-only : specifies that a controller can only handle
+    1-bit data transfers. New devices should use the generic
+    "bus-width = <1>" property.
+  - sdhci,auto-cmd12: specifies that a controller can only handle auto
+    CMD12.
 
 Example:
 
index c7e404b3ef0515b5527583cae877ab48c5d69595..70cd49b1caa8c07e71b7d0855a9469fc989cb7f6 100644 (file)
@@ -3,17 +3,15 @@
 The Enhanced Secure Digital Host Controller on Freescale i.MX family
 provides an interface for MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the sdhci-esdhc-imx driver.
+
 Required properties:
 - compatible : Should be "fsl,<chip>-esdhc"
-- reg : Should contain eSDHC registers location and length
-- interrupts : Should contain eSDHC interrupt
 
 Optional properties:
-- non-removable : Indicate the card is wired to host permanently
 - fsl,cd-internal : Indicate to use controller internal card detection
 - fsl,wp-internal : Indicate to use controller internal write protection
-- cd-gpios : Specify GPIOs for card detection
-- wp-gpios : Specify GPIOs for write protection
 
 Examples:
 
@@ -29,6 +27,6 @@ esdhc@70008000 {
        compatible = "fsl,imx51-esdhc";
        reg = <0x70008000 0x4000>;
        interrupts = <2>;
-       cd-gpios = <&gpio0 6 0>; /* GPIO1_6 */
-       wp-gpios = <&gpio0 5 0>; /* GPIO1_5 */
+       cd-gpios = <&gpio1 6 0>; /* GPIO1_6 */
+       wp-gpios = <&gpio1 5 0>; /* GPIO1_5 */
 };
index d64aea5a42032414fa99d1fa43fb0dc20114c254..0e5e2ec4001dda10fe1b35b57d8ecbe976febf0a 100644 (file)
@@ -1,8 +1,9 @@
 MMC/SD/SDIO slot directly connected to a SPI bus
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the mmc_spi driver.
+
 Required properties:
-- compatible : should be "mmc-spi-slot".
-- reg : should specify SPI address (chip-select number).
 - spi-max-frequency : maximum frequency for this device (Hz).
 - voltage-ranges : two cells are required, first cell specifies minimum
   slot voltage (mV), second cell specifies maximum slot voltage (mV).
@@ -11,8 +12,7 @@ Required properties:
 Optional properties:
 - gpios : may specify GPIOs in this order: Card-Detect GPIO,
   Write-Protect GPIO. Note that this does not follow the
-  binding from mmc.txt, for historic reasons.
-- interrupts : the interrupt of a card detect interrupt.
+  binding from mmc.txt, for historical reasons.
 - interrupt-parent : the phandle for the interrupt controller that
   services interrupts for this device.
 
index 6e70dcde0a71e0f997abb0f5abdf10146aaaefb3..8a6811f4a02f5759e2a793506f1cef40b756e2d8 100644 (file)
@@ -2,13 +2,17 @@ These properties are common to multiple MMC host controllers. Any host
 that requires the respective functionality should implement them using
 these definitions.
 
+Interpreted by the OF core:
+- reg: Registers location and length.
+- interrupts: Interrupts used by the MMC controller.
+
 Required properties:
 - bus-width: Number of data lines, can be <1>, <4>, or <8>
 
 Optional properties:
-- cd-gpios : Specify GPIOs for card detection, see gpio binding
-- wp-gpios : Specify GPIOs for write protection, see gpio binding
-- cd-inverted: when present, polarity on the wp gpio line is inverted
+- cd-gpios: Specify GPIOs for card detection, see gpio binding
+- wp-gpios: Specify GPIOs for write protection, see gpio binding
+- cd-inverted: when present, polarity on the cd gpio line is inverted
 - wp-inverted: when present, polarity on the wp gpio line is inverted
 - non-removable: non-removable slot (like eMMC)
 - max-frequency: maximum operating clock frequency
index 14a81d5261182aa7f2775bc3ef543785122ae494..2b584cae352ae72f093c0e470ad436ada0b5598f 100644 (file)
@@ -1,19 +1,15 @@
 * ARM PrimeCell MultiMedia Card Interface (MMCI) PL180/1
 
-The ARM PrimeCell MMCI PL180 and PL181 provides and interface for
+The ARM PrimeCell MMCI PL180 and PL181 provides an interface for
 reading and writing to MultiMedia and SD cards alike.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the mmci driver.
+
 Required properties:
 - compatible             : contains "arm,pl18x", "arm,primecell".
-- reg                    : contains pl18x registers and length.
-- interrupts             : contains the device IRQ(s).
 - arm,primecell-periphid : contains the PrimeCell Peripheral ID.
 
 Optional properties:
-- wp-gpios               : contains any write protect (ro) gpios
-- cd-gpios               : contains any card detection gpios
-- cd-inverted            : indicates whether the cd gpio is inverted
-- max-frequency          : contains the maximum operating frequency
-- bus-width              : number of data lines, can be <1>, <4>, or <8>
 - mmc-cap-mmc-highspeed  : indicates whether MMC is high speed capable
 - mmc-cap-sd-highspeed   : indicates whether SD is high speed capable
index 14d870a9e3db521c84311ac1fd80b57edd78f0a4..54949f6faedebf3ba54825bd62fb1a1ab254cf95 100644 (file)
@@ -3,16 +3,14 @@
 The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller
 to support MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties in mmc.txt
+and the properties used by the mxsmmc driver.
+
 Required properties:
 - compatible: Should be "fsl,<chip>-mmc".  The supported chips include
   imx23 and imx28.
-- reg: Should contain registers location and length
 - interrupts: Should contain ERROR and DMA interrupts
 - fsl,ssp-dma-channel: APBH DMA channel for the SSP
-- bus-width: Number of data lines, can be <1>, <4>, or <8>
-
-Optional properties:
-- wp-gpios: Specify GPIOs for write protection
 
 Examples:
 
similarity index 67%
rename from Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt
rename to Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
index f77c3031607fbea26a250e3f7fcdd6373089dfff..c6d7b11db9eb00ed81ad3fcff3ddb78c9dbdc072 100644 (file)
@@ -3,15 +3,13 @@
 This controller on Tegra family SoCs provides an interface for MMC, SD,
 and SDIO types of memory cards.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the sdhci-tegra driver.
+
 Required properties:
 - compatible : Should be "nvidia,<chip>-sdhci"
-- reg : Should contain SD/MMC registers location and length
-- interrupts : Should contain SD/MMC interrupt
-- bus-width : Number of data lines, can be <1>, <4>, or <8>
 
 Optional properties:
-- cd-gpios : Specify GPIOs for card detection
-- wp-gpios : Specify GPIOs for write protection
 - power-gpios : Specify GPIOs for power control
 
 Example:
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
new file mode 100644 (file)
index 0000000..dbe98a3
--- /dev/null
@@ -0,0 +1,21 @@
+* Marvell sdhci-pxa v2/v3 controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
+
+Required properties:
+- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc".
+
+Optional properties:
+- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
+
+Example:
+
+sdhci@d4280800 {
+       compatible = "mrvl,pxav3-mmc";
+       reg = <0xd4280800 0x800>;
+       bus-width = <8>;
+       interrupts = <27>;
+       non-removable;
+       mrvl,clk-delay-cycles = <31>;
+};
index 8a53958c9a9f50e71073daa1b8aa0650308ea13c..be76a23b34c408133bb1d397c2c3395cac59c66a 100644 (file)
@@ -3,21 +3,20 @@
 The Highspeed MMC Host Controller on TI OMAP family
 provides an interface for MMC, SD, and SDIO types of memory cards.
 
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the omap_hsmmc driver.
+
 Required properties:
 - compatible:
  Should be "ti,omap2-hsmmc", for OMAP2 controllers
  Should be "ti,omap3-hsmmc", for OMAP3 controllers
  Should be "ti,omap4-hsmmc", for OMAP4 controllers
 - ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
-- reg : should contain hsmmc registers location and length
 
 Optional properties:
 ti,dual-volt: boolean, supports dual voltage cards
 <supply-name>-supply: phandle to the regulator device tree node
 "supply-name" examples are "vmmc", "vmmc_aux" etc
-bus-width: Number of data lines, default assumed is 1 if the property is missing.
-cd-gpios: GPIOs for card detection
-wp-gpios: GPIOs for write protection
 ti,non-removable: non-removable slot (like eMMC)
 ti,needs-special-reset: Requires a special softreset sequence
 
index 7ab9e1a2d8bec19fac2283b5703fae60d2858998..4616fc28ee86e83793550a0ceda9fa25e4b46167 100644 (file)
@@ -19,6 +19,6 @@ ethernet@83fec000 {
        reg = <0x83fec000 0x4000>;
        interrupts = <87>;
        phy-mode = "mii";
-       phy-reset-gpios = <&gpio1 14 0>; /* GPIO2_14 */
+       phy-reset-gpios = <&gpio2 14 0>; /* GPIO2_14 */
        local-mac-address = [00 04 9F 01 1B B9];
 };
index 82b43f9158579cdf94b4134ab59d111f45c08a11..a4119f6422d9527e1a5e50d672c70b62aa9d0ad3 100644 (file)
@@ -1626,3 +1626,5 @@ MX6Q_PAD_SD2_DAT3__PCIE_CTRL_MUX_11               1587
 MX6Q_PAD_SD2_DAT3__GPIO_1_12                   1588
 MX6Q_PAD_SD2_DAT3__SJC_DONE                    1589
 MX6Q_PAD_SD2_DAT3__ANATOP_TESTO_3              1590
+MX6Q_PAD_ENET_RX_ER__ANATOP_USBOTG_ID          1591
+MX6Q_PAD_GPIO_1__ANATOP_USBOTG_ID              1592
index 2f5b6b1ba15f9c97c64b483fc1ad8f1a31ee6053..4fae41d547984297d0f427d22baa672a1ffedea2 100644 (file)
@@ -10,6 +10,7 @@ Optional properties:
 If this property is missing, the default assumed is Active low.
 - gpio-open-drain: GPIO is open drain type.
   If this property is missing then default assumption is false.
+-vin-supply: Input supply name.
 
 Any property defined as part of the core regulator
 binding, defined in regulator.txt, can also be used.
@@ -29,4 +30,5 @@ Example:
                enable-active-high;
                regulator-boot-on;
                gpio-open-drain;
+               vin-supply = <&parent_reg>;
        };
index 5b7a408acdaa2ddd09aacab5d8ab402f52f00389..66ece3f87bbc09d755973b7580944fea3cb60971 100644 (file)
@@ -10,6 +10,11 @@ Optional properties:
 - regulator-always-on: boolean, regulator should never be disabled
 - regulator-boot-on: bootloader/firmware enabled regulator
 - <name>-supply: phandle to the parent supply/regulator node
+- regulator-ramp-delay: ramp delay for regulator(in uV/uS)
+- regulator-compatible: If a regulator chip contains multiple
+  regulators, and if the chip's binding contains a child node that
+  describes each regulator, then this property indicates which regulator
+  this child node is intended to configure.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/regulator/tps65217.txt b/Documentation/devicetree/bindings/regulator/tps65217.txt
new file mode 100644 (file)
index 0000000..0487e96
--- /dev/null
@@ -0,0 +1,91 @@
+TPS65217 family of regulators
+
+Required properties:
+- compatible: "ti,tps65217"
+- reg: I2C slave address
+- regulators: list of regulators provided by this controller, must be named
+  after their hardware counterparts: dcdc[1-3] and ldo[1-4]
+- 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
+  using the standard binding for regulators found at
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+
+  The valid names for regulators are:
+  tps65217: dcdc1, dcdc2, dcdc3, ldo1, ldo2, ldo3 and ldo4
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+       tps: tps@24 {
+               compatible = "ti,tps65217";
+
+               regulators {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       dcdc1_reg: regulator@0 {
+                               reg = <0>;
+                               regulator-compatible = "dcdc1";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       dcdc2_reg: regulator@1 {
+                               reg = <1>;
+                               regulator-compatible = "dcdc2";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       dcdc3_reg: regulator@2 {
+                               reg = <2>;
+                               regulator-compatible = "dcdc3";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <1500000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo1_reg: regulator@3 {
+                               reg = <3>;
+                               regulator-compatible = "ldo1";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo2_reg: regulator@4 {
+                               reg = <4>;
+                               regulator-compatible = "ldo2";
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo3_reg: regulator@5 {
+                               reg = <5>;
+                               regulator-compatible = "ldo3";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       ldo4_reg: regulator@6 {
+                               reg = <6>;
+                               regulator-compatible = "ldo4";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+               };
+       };
index 0fcabaa3baa344fa9a2ec676bfec2ab999a38891..d156e1b5db1233c5ffdb2c0f54e1f5bd6234da34 100644 (file)
@@ -6,8 +6,17 @@ Required properties:
 - interrupts: the interrupt outputs of the controller
 - #gpio-cells: number of cells to describe a GPIO
 - gpio-controller: mark the device as a GPIO controller
-- regulators: list of regulators provided by this controller, must be named
-  after their hardware counterparts: sm[0-2], ldo[0-9] and ldo_rtc
+- regulators: list of regulators provided by this controller, must have
+  property "regulator-compatible" to match their hardware counterparts:
+  sm[0-2], ldo[0-9] and ldo_rtc
+- sm0-supply: The input supply for the SM0.
+- sm1-supply: The input supply for the SM1.
+- sm2-supply: The input supply for the SM2.
+- vinldo01-supply: The input supply for the LDO1 and LDO2
+- vinldo23-supply: The input supply for the LDO2 and LDO3
+- vinldo4-supply: The input supply for the LDO4
+- vinldo678-supply: The input supply for the LDO6, LDO7 and LDO8
+- vinldo9-supply: The input supply for the LDO9
 
 Each regulator is defined using the standard binding for regulators.
 
@@ -21,75 +30,113 @@ Example:
                #gpio-cells = <2>;
                gpio-controller;
 
+               sm0-supply = <&some_reg>;
+               sm1-supply = <&some_reg>;
+               sm2-supply = <&some_reg>;
+               vinldo01-supply = <...>;
+               vinldo23-supply = <...>;
+               vinldo4-supply = <...>;
+               vinldo678-supply = <...>;
+               vinldo9-supply = <...>;
+
                regulators {
-                       sm0_reg: sm0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       sm0_reg: regulator@0 {
+                               reg = <0>;
+                               regulator-compatible = "sm0";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-boot-on;
                                regulator-always-on;
                        };
 
-                       sm1_reg: sm1 {
+                       sm1_reg: regulator@1 {
+                               reg = <1>;
+                               regulator-compatible = "sm1";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-boot-on;
                                regulator-always-on;
                        };
 
-                       sm2_reg: sm2 {
+                       sm2_reg: regulator@2 {
+                               reg = <2>;
+                               regulator-compatible = "sm2";
                                regulator-min-microvolt = <3000000>;
                                regulator-max-microvolt = <4550000>;
                                regulator-boot-on;
                                regulator-always-on;
                        };
 
-                       ldo0_reg: ldo0 {
+                       ldo0_reg: regulator@3 {
+                               reg = <3>;
+                               regulator-compatible = "ldo0";
                                regulator-name = "PCIE CLK";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo1_reg: ldo1 {
+                       ldo1_reg: regulator@4 {
+                               reg = <4>;
+                               regulator-compatible = "ldo1";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
                        };
 
-                       ldo2_reg: ldo2 {
+                       ldo2_reg: regulator@5 {
+                               reg = <5>;
+                               regulator-compatible = "ldo2";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
                        };
 
-                       ldo3_reg: ldo3 {
+                       ldo3_reg: regulator@6 {
+                               reg = <6>;
+                               regulator-compatible = "ldo3";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo4_reg: ldo4 {
+                       ldo4_reg: regulator@7 {
+                               reg = <7>;
+                               regulator-compatible = "ldo4";
                                regulator-min-microvolt = <1700000>;
                                regulator-max-microvolt = <2475000>;
                        };
 
-                       ldo5_reg: ldo5 {
+                       ldo5_reg: regulator@8 {
+                               reg = <8>;
+                               regulator-compatible = "ldo5";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo6_reg: ldo6 {
+                       ldo6_reg: regulator@9 {
+                               reg = <9>;
+                               regulator-compatible = "ldo6";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo7_reg: ldo7 {
+                       ldo7_reg: regulator@10 {
+                               reg = <10>;
+                               regulator-compatible = "ldo7";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo8_reg: ldo8 {
+                       ldo8_reg: regulator@11 {
+                               reg = <11>;
+                               regulator-compatible = "ldo8";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo9_reg: ldo9 {
+                       ldo9_reg: regulator@12 {
+                               reg = <12>;
+                               regulator-compatible = "ldo9";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
index 0c3395d55ac19afde8c334fc096dc937a1e9ca19..658749b90b970e0d309c656d3c389d9730f81a1b 100644 (file)
@@ -15,7 +15,6 @@ For twl6030 regulators/LDOs
   - "ti,twl6030-vusb" for VUSB LDO
   - "ti,twl6030-v1v8" for V1V8 LDO
   - "ti,twl6030-v2v1" for V2V1 LDO
-  - "ti,twl6030-clk32kg" for CLK32KG RESOURCE
   - "ti,twl6030-vdd1" for VDD1 SMPS
   - "ti,twl6030-vdd2" for VDD2 SMPS
   - "ti,twl6030-vdd3" for VDD3 SMPS
diff --git a/Documentation/devicetree/bindings/rtc/dw-apb.txt b/Documentation/devicetree/bindings/rtc/dw-apb.txt
new file mode 100644 (file)
index 0000000..93e2b0f
--- /dev/null
@@ -0,0 +1,25 @@
+* Designware APB timer
+
+Required properties:
+- compatible: "snps,dw-apb-timer-sp" or "snps,dw-apb-timer-osc"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: IRQ line for the timer.
+- clock-frequency: The frequency in HZ of the timer.
+- clock-freq: For backwards compatibility with picoxcell
+
+Example:
+
+               timer1: timer@ffc09000 {
+                               compatible = "snps,dw-apb-timer-sp";
+                               interrupts = <0 168 4>;
+                               clock-frequency = <200000000>;
+                               reg = <0xffc09000 0x1000>;
+                       };
+
+               timer2: timer@ffd00000 {
+                               compatible = "snps,dw-apb-timer-osc";
+                               interrupts = <0 169 4>;
+                               clock-frequency = <200000000>;
+                               reg = <0xffd00000 0x1000>;
+                       };
diff --git a/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt b/Documentation/devicetree/bindings/rtc/stmp3xxx-rtc.txt
new file mode 100644 (file)
index 0000000..b800070
--- /dev/null
@@ -0,0 +1,16 @@
+* STMP3xxx/i.MX28 Time Clock controller
+
+Required properties:
+- compatible: should be one of the following.
+    * "fsl,stmp3xxx-rtc"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- interrupts: rtc alarm interrupt
+
+Example:
+
+rtc@80056000 {
+       compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc";
+       reg = <0x80056000 2000>;
+       interrupts = <29>;
+};
index 9841057d112bb6e4c46299166ef7c5a9a6da5521..4256a6df9b79355d8c17f5f393c3956d6a5a78ca 100644 (file)
@@ -17,6 +17,6 @@ ecspi@70010000 {
        reg = <0x70010000 0x4000>;
        interrupts = <36>;
        fsl,spi-num-chipselects = <2>;
-       cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
-                  <&gpio3 25 0>; /* GPIO4_25 */
+       cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */
+                  <&gpio3 25 0>; /* GPIO3_25 */
 };
diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt
new file mode 100644 (file)
index 0000000..a15ffed
--- /dev/null
@@ -0,0 +1,116 @@
+* Samsung SPI Controller
+
+The Samsung SPI controller is used to interface with various devices such as flash
+and display controllers using the SPI communication interface.
+
+Required SoC Specific Properties:
+
+- compatible: should be one of the following.
+    - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
+    - samsung,s3c6410-spi: for s3c6410 platforms
+    - samsung,s5p6440-spi: for s5p6440 and s5p6450 platforms
+    - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms
+    - samsung,exynos4210-spi: for exynos4 and exynos5 platforms
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: The interrupt number to the cpu. The interrupt specifier format
+  depends on the interrupt controller.
+
+[PRELIMINARY: the dma channel allocation will change once there are
+official DMA bindings]
+
+- tx-dma-channel: The dma channel specifier for tx operations. The format of
+  the dma specifier depends on the dma controller.
+
+- rx-dma-channel: The dma channel specifier for rx operations. The format of
+  the dma specifier depends on the dma controller.
+
+Required Board Specific Properties:
+
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+- gpios: The gpio specifier for clock, mosi and miso interface lines (in the
+  order specified). The format of the gpio specifier depends on the gpio
+  controller.
+
+Optional Board Specific Properties:
+
+- samsung,spi-src-clk: If the spi controller includes a internal clock mux to
+  select the clock source for the spi bus clock, this property can be used to
+  indicate the clock to be used for driving the spi bus clock. If not specified,
+  the clock number 0 is used as default.
+
+- num-cs: Specifies the number of chip select lines supported. If
+  not specified, the default number of chip select lines is set to 1.
+
+SPI Controller specific data in SPI slave nodes:
+
+- The spi slave nodes should provide the following information which is required
+  by the spi controller.
+
+  - cs-gpio: A gpio specifier that specifies the gpio line used as
+    the slave select line by the spi controller. The format of the gpio
+    specifier depends on the gpio controller.
+
+  - samsung,spi-feedback-delay: The sampling phase shift to be applied on the
+    miso line (to account for any lag in the miso line). The following are the
+    valid values.
+
+      - 0: No phase shift.
+      - 1: 90 degree phase shift sampling.
+      - 2: 180 degree phase shift sampling.
+      - 3: 270 degree phase shift sampling.
+
+Aliases:
+
+- All the SPI controller nodes should be represented in the aliases node using
+  the following format 'spi{n}' where n is a unique number for the alias.
+
+
+Example:
+
+- SoC Specific Portion:
+
+       spi_0: spi@12d20000 {
+               compatible = "samsung,exynos4210-spi";
+               reg = <0x12d20000 0x100>;
+               interrupts = <0 66 0>;
+               tx-dma-channel = <&pdma0 5>;
+               rx-dma-channel = <&pdma0 4>;
+       };
+
+- Board Specific Portion:
+
+       spi_0: spi@12d20000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpios = <&gpa2 4 2 3 0>,
+                       <&gpa2 6 2 3 0>,
+                       <&gpa2 7 2 3 0>;
+
+               w25q80bw@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "w25x80";
+                       reg = <0>;
+                       spi-max-frequency = <10000>;
+
+                       controller-data {
+                               cs-gpio = <&gpa2 5 1 0 3>;
+                               samsung,spi-feedback-delay = <0>;
+                       };
+
+                       partition@0 {
+                               label = "U-Boot";
+                               reg = <0x0 0x40000>;
+                               read-only;
+                       };
+
+                       partition@40000 {
+                               label = "Kernel";
+                               reg = <0x40000 0xc0000>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt b/Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt
new file mode 100644 (file)
index 0000000..2ee903f
--- /dev/null
@@ -0,0 +1,27 @@
+* Freescale MXS Application UART (AUART)
+
+Required properties:
+- compatible : Should be "fsl,<soc>-auart". The supported SoCs include
+  imx23 and imx28.
+- reg : Address and length of the register set for the device
+- interrupts : Should contain the auart interrupt numbers
+
+Example:
+auart0: serial@8006a000 {
+       compatible = "fsl,imx28-auart", "fsl,imx23-auart";
+       reg = <0x8006a000 0x2000>;
+       interrupts = <112 70 71>;
+};
+
+Note: Each auart port should have an alias correctly numbered in "aliases"
+node.
+
+Example:
+
+aliases {
+       serial0 = &auart0;
+       serial1 = &auart1;
+       serial2 = &auart2;
+       serial3 = &auart3;
+       serial4 = &auart4;
+};
index 6eab91747a86a03c45c60d9bdca74fb28215b3a3..db4d3af3643c407ffad6e4ead2dd81d8c4ab36cf 100644 (file)
@@ -3,6 +3,7 @@ Device tree binding vendor prefix registry.  Keep list in alphabetical order.
 This isn't an exhaustive list, but you should add new prefixes to it before
 using them to avoid name-space collisions.
 
+ad     Avionic Design GmbH
 adi    Analog Devices, Inc.
 amcc   Applied Micro Circuits Corporation (APM, formally AMCC)
 apm    Applied Micro Circuits Corporation (APM)
diff --git a/Documentation/devicetree/bindings/watchdog/omap-wdt.txt b/Documentation/devicetree/bindings/watchdog/omap-wdt.txt
new file mode 100644 (file)
index 0000000..c227970
--- /dev/null
@@ -0,0 +1,14 @@
+TI Watchdog Timer (WDT) Controller for OMAP
+
+Required properties:
+compatible:
+- "ti,omap3-wdt" for OMAP3
+- "ti,omap4-wdt" for OMAP4
+- ti,hwmods: Name of the hwmod associated to the WDT
+
+Examples:
+
+wdt2: wdt@4a314000 {
+       compatible = "ti,omap4-wdt", "ti,omap3-wdt";
+       ti,hwmods = "wd_timer2";
+};
index 8e2da1e06e3b2371eb82ef07105e63ad97d224b6..e0cce2a5f820a6327f9ea1558717434c490e8aae 100644 (file)
@@ -9,7 +9,7 @@ be able to use diff(1).
 
 --------------------------- dentry_operations --------------------------
 prototypes:
-       int (*d_revalidate)(struct dentry *, struct nameidata *);
+       int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_hash)(const struct dentry *, const struct inode *,
                        struct qstr *);
        int (*d_compare)(const struct dentry *, const struct inode *,
@@ -37,9 +37,8 @@ d_manage:     no              no              yes (ref-walk)  maybe
 
 --------------------------- inode_operations --------------------------- 
 prototypes:
-       int (*create) (struct inode *,struct dentry *,umode_t, struct nameidata *);
-       struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameid
-ata *);
+       int (*create) (struct inode *,struct dentry *,umode_t, bool);
+       struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
        int (*link) (struct dentry *,struct inode *,struct dentry *);
        int (*unlink) (struct inode *,struct dentry *);
        int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -62,6 +61,9 @@ ata *);
        int (*removexattr) (struct dentry *, const char *);
        int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
        void (*update_time)(struct inode *, struct timespec *, int);
+       int (*atomic_open)(struct inode *, struct dentry *,
+                               struct file *, unsigned open_flag,
+                               umode_t create_mode, int *opened);
 
 locking rules:
        all may block
@@ -89,6 +91,7 @@ listxattr:    no
 removexattr:   yes
 fiemap:                no
 update_time:   no
+atomic_open:   yes
 
        Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
index 8c91d1057d9a141f77c0c64614eb17024d45256f..2bef2b3843d1d4e09ead99fed121de4b2ab92db2 100644 (file)
@@ -355,12 +355,10 @@ protects *all* the dcache state of a given dentry.
 via rcu-walk path walk (basically, if the file can have had a path name in the
 vfs namespace).
 
-       i_dentry and i_rcu share storage in a union, and the vfs expects
-i_dentry to be reinitialized before it is freed, so an:
-
-  INIT_LIST_HEAD(&inode->i_dentry);
-
-must be done in the RCU callback.
+       Even though i_dentry and i_rcu share storage in a union, we will
+initialize the former in inode_init_always(), so just leave it alone in
+the callback.  It used to be necessary to clean it there, but not anymore
+(starting at 3.2).
 
 --
 [recommended]
@@ -433,3 +431,14 @@ release it yourself.
        d_alloc_root() is gone, along with a lot of bugs caused by code
 misusing it.  Replacement: d_make_root(inode).  The difference is,
 d_make_root() drops the reference to inode if dentry allocation fails.  
+
+--
+[mandatory]
+       The witch is dead!  Well, 2/3 of it, anyway.  ->d_revalidate() and
+->lookup() do *not* take struct nameidata anymore; just the flags.
+--
+[mandatory]
+       ->create() doesn't take struct nameidata *; unlike the previous
+two, it gets "is it an O_EXCL or equivalent?" boolean argument.  Note that
+local filesystems can ignore tha argument - they are guaranteed that the
+object doesn't exist.  It's remote/distributed ones that might care...
index efd23f4817044ac9d55932bd9476d309a02918dc..aa754e01464e1c71f55869da9d5222ef763518d7 100644 (file)
@@ -341,8 +341,8 @@ This describes how the VFS can manipulate an inode in your
 filesystem. As of kernel 2.6.22, the following members are defined:
 
 struct inode_operations {
-       int (*create) (struct inode *,struct dentry *, umode_t, struct nameidata *);
-       struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
+       int (*create) (struct inode *,struct dentry *, umode_t, bool);
+       struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
        int (*link) (struct dentry *,struct inode *,struct dentry *);
        int (*unlink) (struct inode *,struct dentry *);
        int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -364,6 +364,9 @@ struct inode_operations {
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        int (*removexattr) (struct dentry *, const char *);
        void (*update_time)(struct inode *, struct timespec *, int);
+       int (*atomic_open)(struct inode *, struct dentry *,
+                               struct file *, unsigned open_flag,
+                               umode_t create_mode, int *opened);
 };
 
 Again, all methods are called without any locks being held, unless
@@ -476,6 +479,14 @@ otherwise noted.
        an inode.  If this is not defined the VFS will update the inode itself
        and call mark_inode_dirty_sync.
 
+  atomic_open: called on the last component of an open.  Using this optional
+       method the filesystem can look up, possibly create and open the file in
+       one atomic operation.  If it cannot perform this (e.g. the file type
+       turned out to be wrong) it may signal this by returning 1 instead of
+       usual 0 or -ve .  This method is only called if the last
+       component is negative or needs lookup.  Cached positive dentries are
+       still handled by f_op->open().
+
 The Address Space Object
 ========================
 
@@ -891,7 +902,7 @@ the VFS uses a default. As of kernel 2.6.22, the following members are
 defined:
 
 struct dentry_operations {
-       int (*d_revalidate)(struct dentry *, struct nameidata *);
+       int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_hash)(const struct dentry *, const struct inode *,
                        struct qstr *);
        int (*d_compare)(const struct dentry *, const struct inode *,
@@ -910,11 +921,11 @@ struct dentry_operations {
        dcache. Most filesystems leave this as NULL, because all their
        dentries in the dcache are valid
 
-       d_revalidate may be called in rcu-walk mode (nd->flags & LOOKUP_RCU).
+       d_revalidate may be called in rcu-walk mode (flags & LOOKUP_RCU).
        If in rcu-walk mode, the filesystem must revalidate the dentry without
        blocking or storing to the dentry, d_parent and d_inode should not be
-       used without care (because they can go NULL), instead nd->inode should
-       be used.
+       used without care (because they can change and, in d_inode case, even
+       become NULL under us).
 
        If a situation is encountered that rcu-walk cannot handle, return
        -ECHILD and it will be called again in ref-walk mode.
index 506c7390c2b90e37b0df7f1b8e93dc7ff2b540fd..13f1aa09b938c09c91421ad55dc168ef67cd8347 100644 (file)
@@ -86,7 +86,7 @@ There is also a gitweb interface available at
 http://www.kernel.org/git/?p=utils/kernel/kexec/kexec-tools.git
 
 More information about kexec-tools can be found at
-http://www.kernel.org/pub/linux/utils/kernel/kexec/README.html
+http://horms.net/projects/kexec/
 
 3) Unpack the tarball with the tar command, as follows:
 
index a92c5ebf373e2bf4bea68072b58fbc0471ad9c13..12783fa833c38041c94fb02cff34bc011b4d184d 100644 (file)
@@ -2367,6 +2367,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Set maximum number of finished RCU callbacks to process
                        in one batch.
 
+       rcutree.fanout_leaf=    [KNL,BOOT]
+                       Increase the number of CPUs assigned to each
+                       leaf rcu_node structure.  Useful for very large
+                       systems.
+
        rcutree.qhimark=        [KNL,BOOT]
                        Set threshold of queued
                        RCU callbacks over which batch limiting is disabled.
index 872815cd41d30bcc8e57df31b6b283a4872a2690..504dfe4d52eba3541cfa6330d52595d37265a0b7 100644 (file)
@@ -583,9 +583,10 @@ for the given device during all power transitions, instead of the respective
 subsystem-level callbacks.  Specifically, if a device's pm_domain pointer is
 not NULL, the ->suspend() callback from the object pointed to by it will be
 executed instead of its subsystem's (e.g. bus type's) ->suspend() callback and
-anlogously for all of the remaining callbacks.  In other words, power management
-domain callbacks, if defined for the given device, always take precedence over
-the callbacks provided by the device's subsystem (e.g. bus type).
+analogously for all of the remaining callbacks.  In other words, power
+management domain callbacks, if defined for the given device, always take
+precedence over the callbacks provided by the device's subsystem (e.g. bus
+type).
 
 The support for device power management domains is only relevant to platforms
 needing to use the same device driver power management callbacks in many
@@ -598,7 +599,7 @@ it into account in any way.
 Device Low Power (suspend) States
 ---------------------------------
 Device low-power states aren't standard.  One device might only handle
-"on" and "off, while another might support a dozen different versions of
+"on" and "off", while another might support a dozen different versions of
 "on" (how many engines are active?), plus a state that gets back to "on"
 faster than from a full "off".
 
index ac190cf1963e05e310edf6a96df2466f01eb1355..92341b84250dfaf137b89376c115597a4bd9c222 100644 (file)
@@ -33,6 +33,11 @@ echo shutdown > /sys/power/disk; echo disk > /sys/power/state
 
 echo platform > /sys/power/disk; echo disk > /sys/power/state
 
+. If you would like to write hibernation image to swap and then suspend
+to RAM (provided your platform supports it), you can try
+
+echo suspend > /sys/power/disk; echo disk > /sys/power/state
+
 . If you have SATA disks, you'll need recent kernels with SATA suspend
 support. For suspend and resume to work, make sure your disk drivers
 are built into kernel -- not modules. [There's way to make
diff --git a/Documentation/prctl/no_new_privs.txt b/Documentation/prctl/no_new_privs.txt
new file mode 100644 (file)
index 0000000..f7be84f
--- /dev/null
@@ -0,0 +1,57 @@
+The execve system call can grant a newly-started program privileges that
+its parent did not have.  The most obvious examples are setuid/setgid
+programs and file capabilities.  To prevent the parent program from
+gaining these privileges as well, the kernel and user code must be
+careful to prevent the parent from doing anything that could subvert the
+child.  For example:
+
+ - The dynamic loader handles LD_* environment variables differently if
+   a program is setuid.
+
+ - chroot is disallowed to unprivileged processes, since it would allow
+   /etc/passwd to be replaced from the point of view of a process that
+   inherited chroot.
+
+ - The exec code has special handling for ptrace.
+
+These are all ad-hoc fixes.  The no_new_privs bit (since Linux 3.5) is a
+new, generic mechanism to make it safe for a process to modify its
+execution environment in a manner that persists across execve.  Any task
+can set no_new_privs.  Once the bit is set, it is inherited across fork,
+clone, and execve and cannot be unset.  With no_new_privs set, execve
+promises not to grant the privilege to do anything that could not have
+been done without the execve call.  For example, the setuid and setgid
+bits will no longer change the uid or gid; file capabilities will not
+add to the permitted set, and LSMs will not relax constraints after
+execve.
+
+To set no_new_privs, use prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0).
+
+Be careful, though: LSMs might also not tighten constraints on exec
+in no_new_privs mode.  (This means that setting up a general-purpose
+service launcher to set no_new_privs before execing daemons may
+interfere with LSM-based sandboxing.)
+
+Note that no_new_privs does not prevent privilege changes that do not
+involve execve.  An appropriately privileged task can still call
+setuid(2) and receive SCM_RIGHTS datagrams.
+
+There are two main use cases for no_new_privs so far:
+
+ - Filters installed for the seccomp mode 2 sandbox persist across
+   execve and can change the behavior of newly-executed programs.
+   Unprivileged users are therefore only allowed to install such filters
+   if no_new_privs is set.
+
+ - By itself, no_new_privs can be used to reduce the attack surface
+   available to an unprivileged user.  If everything running with a
+   given uid has no_new_privs set, then that uid will be unable to
+   escalate its privileges by directly attacking setuid, setgid, and
+   fcap-using binaries; it will need to compromise something without the
+   no_new_privs bit set first.
+
+In the future, other potentially dangerous kernel features could become
+available to unprivileged tasks if no_new_privs is set.  In principle,
+several options to unshare(2) and clone(2) would be safe when
+no_new_privs is set, and no_new_privs + chroot is considerable less
+dangerous than chroot by itself.
index 930126698a0f5b0f6e2c458b53604d581b201063..2c9948379469c1dba5f8c7ef711567067727ff08 100644 (file)
@@ -1930,6 +1930,23 @@ The "pte_enc" field provides a value that can OR'ed into the hash
 PTE's RPN field (ie, it needs to be shifted left by 12 to OR it
 into the hash PTE second double word).
 
+4.75 KVM_IRQFD
+
+Capability: KVM_CAP_IRQFD
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_irqfd (in)
+Returns: 0 on success, -1 on error
+
+Allows setting an eventfd to directly trigger a guest interrupt.
+kvm_irqfd.fd specifies the file descriptor to use as the eventfd and
+kvm_irqfd.gsi specifies the irqchip pin toggled by this event.  When
+an event is tiggered on the eventfd, an interrupt is injected into
+the guest using the specified gsi pin.  The irqfd is removed using
+the KVM_IRQFD_FLAG_DEASSIGN flag, specifying both kvm_irqfd.fd
+and kvm_irqfd.gsi.
+
+
 5. The kvm_run structure
 ------------------------
 
index ab55a785d4275ad33b2014bebcbf492300c0f898..fe2fa33e2831fef5638981b7553de62d4fa335d1 100644 (file)
@@ -3451,13 +3451,14 @@ S:      Supported
 F:     drivers/idle/i7300_idle.c
 
 IEEE 802.15.4 SUBSYSTEM
+M:     Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
 M:     Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
-M:     Sergey Lapin <slapin@ossfans.org>
 L:     linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
 W:     http://apps.sourceforge.net/trac/linux-zigbee
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
 S:     Maintained
 F:     net/ieee802154/
+F:     net/mac802154/
 F:     drivers/ieee802154/
 
 IIO SUBSYSTEM AND DRIVERS
@@ -4672,8 +4673,8 @@ L:        netfilter@vger.kernel.org
 L:     coreteam@netfilter.org
 W:     http://www.netfilter.org/
 W:     http://www.iptables.org/
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-2.6.git
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next-2.6.git
+T:     git git://1984.lsi.us.es/nf
+T:     git git://1984.lsi.us.es/nf-next
 S:     Supported
 F:     include/linux/netfilter*
 F:     include/linux/netfilter/
@@ -4875,6 +4876,7 @@ M:        Kevin Hilman <khilman@ti.com>
 L:     linux-omap@vger.kernel.org
 S:     Maintained
 F:     arch/arm/*omap*/*pm*
+F:     drivers/cpufreq/omap-cpufreq.c
 
 OMAP POWERDOMAIN/CLOCKDOMAIN SOC ADAPTATION LAYER SUPPORT
 M:     Rajendra Nayak <rnayak@ti.com>
@@ -5581,7 +5583,7 @@ F:        Documentation/networking/LICENSE.qla3xxx
 F:     drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
-M:     Anirban Chakraborty <anirban.chakraborty@qlogic.com>
+M:     Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
 M:     Sony Chacko <sony.chacko@qlogic.com>
 M:     linux-driver@qlogic.com
 L:     netdev@vger.kernel.org
@@ -5589,7 +5591,6 @@ S:        Supported
 F:     drivers/net/ethernet/qlogic/qlcnic/
 
 QLOGIC QLGE 10Gb ETHERNET DRIVER
-M:     Anirban Chakraborty <anirban.chakraborty@qlogic.com>
 M:     Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
 M:     Ron Mercer <ron.mercer@qlogic.com>
 M:     linux-driver@qlogic.com
@@ -5927,7 +5928,7 @@ M:        Ingo Molnar <mingo@redhat.com>
 M:     Peter Zijlstra <peterz@infradead.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
 S:     Maintained
-F:     kernel/sched*
+F:     kernel/sched/
 F:     include/linux/sched.h
 
 SCORE ARCHITECTURE
index 81ea15450049e114f74bb0c753955b5b053addb4..4bb09e1b1230d33d9328c2a67ba32aff22ebde7d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 5
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION =
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
index dfeca559d700d0f686820593443801efad5db92e..b1639621689693d478313e45c90a2b5faddeaab5 100644 (file)
@@ -279,6 +279,7 @@ config ARCH_INTEGRATOR
        select ICST
        select GENERIC_CLOCKEVENTS
        select PLAT_VERSATILE
+       select PLAT_VERSATILE_CLOCK
        select PLAT_VERSATILE_FPGA_IRQ
        select NEED_MACH_IO_H
        select NEED_MACH_MEMORY_H
@@ -296,6 +297,7 @@ config ARCH_REALVIEW
        select GENERIC_CLOCKEVENTS
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select PLAT_VERSATILE
+       select PLAT_VERSATILE_CLOCK
        select PLAT_VERSATILE_CLCD
        select ARM_TIMER_SP804
        select GPIO_PL061 if GPIOLIB
@@ -314,6 +316,7 @@ config ARCH_VERSATILE
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select NEED_MACH_IO_H if PCI
        select PLAT_VERSATILE
+       select PLAT_VERSATILE_CLOCK
        select PLAT_VERSATILE_CLCD
        select PLAT_VERSATILE_FPGA_IRQ
        select ARM_TIMER_SP804
@@ -326,7 +329,7 @@ config ARCH_VEXPRESS
        select ARM_AMBA
        select ARM_TIMER_SP804
        select CLKDEV_LOOKUP
-       select HAVE_MACH_CLKDEV
+       select COMMON_CLK
        select GENERIC_CLOCKEVENTS
        select HAVE_CLK
        select HAVE_PATA_PLATFORM
@@ -334,6 +337,7 @@ config ARCH_VEXPRESS
        select NO_IOPORT
        select PLAT_VERSATILE
        select PLAT_VERSATILE_CLCD
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
        help
          This enables support for the ARM Ltd Versatile Express boards.
 
@@ -598,6 +602,7 @@ config ARCH_LPC32XX
        select CLKDEV_LOOKUP
        select GENERIC_CLOCKEVENTS
        select USE_OF
+       select HAVE_PWM
        help
          Support for the NXP LPC32XX family of processors
 
@@ -689,6 +694,7 @@ config ARCH_PICOXCELL
        select ARM_VIC
        select CPU_V6K
        select DW_APB_TIMER
+       select DW_APB_TIMER_OF
        select GENERIC_CLOCKEVENTS
        select GENERIC_GPIO
        select HAVE_TCM
@@ -944,7 +950,7 @@ config ARCH_NOMADIK
        select ARM_AMBA
        select ARM_VIC
        select CPU_ARM926T
-       select CLKDEV_LOOKUP
+       select COMMON_CLK
        select GENERIC_CLOCKEVENTS
        select PINCTRL
        select MIGHT_HAVE_CACHE_L2X0
@@ -967,6 +973,7 @@ config ARCH_DAVINCI
 
 config ARCH_OMAP
        bool "TI OMAP"
+       depends on MMU
        select HAVE_CLK
        select ARCH_REQUIRE_GPIOLIB
        select ARCH_HAS_CPUFREQ
@@ -1054,8 +1061,6 @@ source "arch/arm/mach-kirkwood/Kconfig"
 
 source "arch/arm/mach-ks8695/Kconfig"
 
-source "arch/arm/mach-lpc32xx/Kconfig"
-
 source "arch/arm/mach-msm/Kconfig"
 
 source "arch/arm/mach-mv78xx0/Kconfig"
index 01a134141216a1a02f5fec43defa8768ad72fa26..a03b5a7059e2d059a34d7655fc6be7fe57ba1676 100644 (file)
@@ -310,6 +310,32 @@ choice
                  The uncompressor code port configuration is now handled
                  by CONFIG_S3C_LOWLEVEL_UART_PORT.
 
+       config DEBUG_VEXPRESS_UART0_DETECT
+               bool "Autodetect UART0 on Versatile Express Cortex-A core tiles"
+               depends on ARCH_VEXPRESS && CPU_CP15_MMU
+               help
+                 This option enables a simple heuristic which tries to determine
+                 the motherboard's memory map variant (original or RS1) and then
+                 choose the relevant UART0 base address.
+
+                 Note that this will only work with standard A-class core tiles,
+                 and may fail with non-standard SMM or custom software models.
+
+       config DEBUG_VEXPRESS_UART0_CA9
+               bool "Use PL011 UART0 at 0x10009000 (V2P-CA9 core tile)"
+               depends on ARCH_VEXPRESS
+               help
+                 This option selects UART0 at 0x10009000. Except for custom models,
+                 this applies only to the V2P-CA9 tile.
+
+       config DEBUG_VEXPRESS_UART0_RS1
+               bool "Use PL011 UART0 at 0x1c090000 (RS1 complaint tiles)"
+               depends on ARCH_VEXPRESS
+               help
+                 This option selects UART0 at 0x1c090000. This applies to most
+                 of the tiles using the RS1 memory map, including all new A-class
+                 core tiles, FPGA-based SMMs and software models.
+
        config DEBUG_LL_UART_NONE
                bool "No low-level debugging UART"
                help
diff --git a/arch/arm/boot/dts/aks-cdu.dts b/arch/arm/boot/dts/aks-cdu.dts
new file mode 100644 (file)
index 0000000..29b9f15
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * aks-cdu.dts - Device Tree file for AK signal CDU
+ *
+ * Copyright (C) 2012 AK signal Brno a.s.
+ *               2012 Jiri Prchal <jiri.prchal@aksignal.cz>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/dts-v1/;
+
+/include/ "ge863-pro3.dtsi"
+
+/ {
+       chosen {
+               bootargs = "console=ttyS0,115200 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs";
+       };
+
+       ahb {
+               apb {
+                       usart0: serial@fffb0000 {
+                               status = "okay";
+                       };
+
+                       usart1: serial@fffb4000 {
+                               status = "okay";
+                               linux,rs485-enabled-at-boot-time;
+                               rs485-rts-delay = <0 0>;
+                               };
+
+                       usart2: serial@fffb8000 {
+                               status = "okay";
+                               linux,rs485-enabled-at-boot-time;
+                               rs485-rts-delay = <0 0>;
+                       };
+
+                       usart3: serial@fffd0000 {
+                               status = "okay";
+                               linux,rs485-enabled-at-boot-time;
+                               rs485-rts-delay = <0 0>;
+                       };
+
+                       macb0: ethernet@fffc4000 {
+                               phy-mode = "rmii";
+                               status = "okay";
+                       };
+
+                       usb1: gadget@fffa4000 {
+                               atmel,vbus-gpio = <&pioC 15 0>;
+                               status = "okay";
+                       };
+               };
+
+               usb0: ohci@00500000 {
+                       num-ports = <2>;
+                       status = "okay";
+               };
+
+               nand0: nand@40000000 {
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "soft";
+                       nand-on-flash-bbt;
+                       status = "okay";
+
+                       bootstrap@0 {
+                               label = "bootstrap";
+                               reg = <0x0 0x40000>;
+                       };
+
+                       uboot@40000 {
+                               label = "uboot";
+                               reg = <0x40000 0x80000>;
+                       };
+                       ubootenv@c0000 {
+                               label = "ubootenv";
+                               reg = <0xc0000 0x40000>;
+                       };
+                       kernel@100000 {
+                               label = "kernel";
+                               reg = <0x100000 0x400000>;
+                       };
+                       rootfs@500000 {
+                               label = "rootfs";
+                               reg = <0x500000 0x7b00000>;
+                       };
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               red {
+                       gpios = <&pioC 10 0>;
+                       linux,default-trigger = "none";
+               };
+
+               green {
+                       gpios = <&pioA 5 1>;
+                       linux,default-trigger = "none";
+                       default-state = "on";
+               };
+
+               yellow {
+                       gpios = <&pioB 20 1>;
+                       linux,default-trigger = "none";
+               };
+
+               blue {
+                       gpios = <&pioB 21 1>;
+                       linux,default-trigger = "none";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
new file mode 100644 (file)
index 0000000..a9af4db
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+/dts-v1/;
+
+/include/ "am33xx.dtsi"
+
+/ {
+       model = "TI AM335x BeagleBone";
+       compatible = "ti,am335x-bone", "ti,am33xx";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x10000000>; /* 256 MB */
+       };
+};
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
new file mode 100644 (file)
index 0000000..d6a97d9
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+/dts-v1/;
+
+/include/ "am33xx.dtsi"
+
+/ {
+       model = "TI AM335x EVM";
+       compatible = "ti,am335x-evm", "ti,am33xx";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x10000000>; /* 256 MB */
+       };
+};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
new file mode 100644 (file)
index 0000000..59509c4
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Device Tree Source for AM33XX SoC
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+       compatible = "ti,am33xx";
+
+       aliases {
+               serial0 = &uart1;
+               serial1 = &uart2;
+               serial2 = &uart3;
+               serial3 = &uart4;
+               serial4 = &uart5;
+               serial5 = &uart6;
+       };
+
+       cpus {
+               cpu@0 {
+                       compatible = "arm,cortex-a8";
+               };
+       };
+
+       /*
+        * The soc node represents the soc top level view. It is uses for IPs
+        * that are not memory mapped in the MPU view or for the MPU itself.
+        */
+       soc {
+               compatible = "ti,omap-infra";
+               mpu {
+                       compatible = "ti,omap3-mpu";
+                       ti,hwmods = "mpu";
+               };
+       };
+
+       /*
+        * XXX: Use a flat representation of the AM33XX interconnect.
+        * The real AM33XX interconnect network is quite complex.Since
+        * that will not bring real advantage to represent that in DT
+        * for the moment, just use a fake OCP bus entry to represent
+        * the whole bus hierarchy.
+        */
+       ocp {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               ti,hwmods = "l3_main";
+
+               intc: interrupt-controller@48200000 {
+                       compatible = "ti,omap2-intc";
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+                       ti,intc-size = <128>;
+                       reg = <0x48200000 0x1000>;
+               };
+
+               gpio1: gpio@44e07000 {
+                       compatible = "ti,omap4-gpio";
+                       ti,hwmods = "gpio1";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+               };
+
+               gpio2: gpio@4804C000 {
+                       compatible = "ti,omap4-gpio";
+                       ti,hwmods = "gpio2";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+               };
+
+               gpio3: gpio@481AC000 {
+                       compatible = "ti,omap4-gpio";
+                       ti,hwmods = "gpio3";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+               };
+
+               gpio4: gpio@481AE000 {
+                       compatible = "ti,omap4-gpio";
+                       ti,hwmods = "gpio4";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+               };
+
+               uart1: serial@44E09000 {
+                       compatible = "ti,omap3-uart";
+                       ti,hwmods = "uart1";
+                       clock-frequency = <48000000>;
+               };
+
+               uart2: serial@48022000 {
+                       compatible = "ti,omap3-uart";
+                       ti,hwmods = "uart2";
+                       clock-frequency = <48000000>;
+               };
+
+               uart3: serial@48024000 {
+                       compatible = "ti,omap3-uart";
+                       ti,hwmods = "uart3";
+                       clock-frequency = <48000000>;
+               };
+
+               uart4: serial@481A6000 {
+                       compatible = "ti,omap3-uart";
+                       ti,hwmods = "uart4";
+                       clock-frequency = <48000000>;
+               };
+
+               uart5: serial@481A8000 {
+                       compatible = "ti,omap3-uart";
+                       ti,hwmods = "uart5";
+                       clock-frequency = <48000000>;
+               };
+
+               uart6: serial@481AA000 {
+                       compatible = "ti,omap3-uart";
+                       ti,hwmods = "uart6";
+                       clock-frequency = <48000000>;
+               };
+
+               i2c1: i2c@44E0B000 {
+                       compatible = "ti,omap4-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c1";
+               };
+
+               i2c2: i2c@4802A000 {
+                       compatible = "ti,omap4-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c2";
+               };
+
+               i2c3: i2c@4819C000 {
+                       compatible = "ti,omap4-i2c";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ti,hwmods = "i2c3";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/am3517-evm.dts b/arch/arm/boot/dts/am3517-evm.dts
new file mode 100644 (file)
index 0000000..474f760
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+/dts-v1/;
+
+/include/ "omap3.dtsi"
+
+/ {
+       model = "TI AM3517 EVM (AM3517/05)";
+       compatible = "ti,am3517-evm", "ti,omap3";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x10000000>; /* 256 MB */
+       };
+};
+
+&i2c1 {
+       clock-frequency = <400000>;
+};
+
+&i2c2 {
+       clock-frequency = <400000>;
+};
+
+&i2c3 {
+       clock-frequency = <400000>;
+};
index f449efc9825fd711d485b57318adf02b47e01f3e..66389c1c6f6297e50c8ae3b944d7311dcbb26b6c 100644 (file)
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <2>;
+                               #interrupt-cells = <3>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                reg = <0xfffff000 0x200>;
+                               atmel,external-irqs = <29 30 31>;
                        };
 
                        ramc0: ramc@ffffea00 {
                        pit: timer@fffffd30 {
                                compatible = "atmel,at91sam9260-pit";
                                reg = <0xfffffd30 0xf>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                        };
 
                        tcb0: timer@fffa0000 {
                                compatible = "atmel,at91rm9200-tcb";
                                reg = <0xfffa0000 0x100>;
-                               interrupts = <17 4 18 4 19 4>;
+                               interrupts = <17 4 0 18 4 0 19 4 0>;
                        };
 
                        tcb1: timer@fffdc000 {
                                compatible = "atmel,at91rm9200-tcb";
                                reg = <0xfffdc000 0x100>;
-                               interrupts = <26 4 27 4 28 4>;
+                               interrupts = <26 4 0 27 4 0 28 4 0>;
                        };
 
                        pioA: gpio@fffff400 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff400 0x100>;
-                               interrupts = <2 4>;
+                               interrupts = <2 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioB: gpio@fffff600 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff600 0x100>;
-                               interrupts = <3 4>;
+                               interrupts = <3 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioC: gpio@fffff800 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff800 0x100>;
-                               interrupts = <4 4>;
+                               interrupts = <4 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                                status = "disabled";
                        };
 
                        usart0: serial@fffb0000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb0000 0x200>;
-                               interrupts = <6 4>;
+                               interrupts = <6 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@fffb4000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb4000 0x200>;
-                               interrupts = <7 4>;
+                               interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@fffb8000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffb8000 0x200>;
-                               interrupts = <8 4>;
+                               interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart3: serial@fffd0000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd0000 0x200>;
-                               interrupts = <23 4>;
+                               interrupts = <23 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart4: serial@fffd4000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd4000 0x200>;
-                               interrupts = <24 4>;
+                               interrupts = <24 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart5: serial@fffd8000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffd8000 0x200>;
-                               interrupts = <25 4>;
+                               interrupts = <25 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@fffc4000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffc4000 0x100>;
-                               interrupts = <21 4>;
+                               interrupts = <21 4 3>;
                                status = "disabled";
                        };
 
                        usb1: gadget@fffa4000 {
                                compatible = "atmel,at91rm9200-udc";
                                reg = <0xfffa4000 0x4000>;
-                               interrupts = <10 4>;
+                               interrupts = <10 4 2>;
                                status = "disabled";
                        };
 
                        adc0: adc@fffe0000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xfffe0000 0x100>;
-                               interrupts = <5 4>;
+                               interrupts = <5 4 0>;
                                atmel,adc-use-external-triggers;
                                atmel,adc-channels-used = <0xf>;
                                atmel,adc-vref = <3300>;
                usb0: ohci@00500000 {
                        compatible = "atmel,at91rm9200-ohci", "usb-ohci";
                        reg = <0x00500000 0x100000>;
-                       interrupts = <20 4>;
+                       interrupts = <20 4 2>;
                        status = "disabled";
                };
        };
index 0209913a65a2001dafea2bacda1ce741fa227872..b460d6ce9eb592da5191871b40b2d3433156bcef 100644 (file)
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <2>;
+                               #interrupt-cells = <3>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                reg = <0xfffff000 0x200>;
+                               atmel,external-irqs = <30 31>;
                        };
 
                        pmc: pmc@fffffc00 {
                        pit: timer@fffffd30 {
                                compatible = "atmel,at91sam9260-pit";
                                reg = <0xfffffd30 0xf>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                        };
 
                        tcb0: timer@fff7c000 {
                                compatible = "atmel,at91rm9200-tcb";
                                reg = <0xfff7c000 0x100>;
-                               interrupts = <19 4>;
+                               interrupts = <19 4 0>;
                        };
 
                        rstc@fffffd00 {
@@ -90,7 +91,7 @@
                        pioA: gpio@fffff200 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff200 0x100>;
-                               interrupts = <2 4>;
+                               interrupts = <2 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioB: gpio@fffff400 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff400 0x100>;
-                               interrupts = <3 4>;
+                               interrupts = <3 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioC: gpio@fffff600 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff600 0x100>;
-                               interrupts = <4 4>;
+                               interrupts = <4 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioD: gpio@fffff800 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff800 0x100>;
-                               interrupts = <4 4>;
+                               interrupts = <4 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioE: gpio@fffffa00 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffffa00 0x100>;
-                               interrupts = <4 4>;
+                               interrupts = <4 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        dbgu: serial@ffffee00 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xffffee00 0x200>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                                status = "disabled";
                        };
 
                        usart0: serial@fff8c000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff8c000 0x200>;
-                               interrupts = <7 4>;
+                               interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@fff90000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff90000 0x200>;
-                               interrupts = <8 4>;
+                               interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@fff94000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff94000 0x200>;
-                               interrupts = <9 4>;
+                               interrupts = <9 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@fffbc000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffbc000 0x100>;
-                               interrupts = <21 4>;
+                               interrupts = <21 4 3>;
                                status = "disabled";
                        };
 
                        usb1: gadget@fff78000 {
                                compatible = "atmel,at91rm9200-udc";
                                reg = <0xfff78000 0x4000>;
-                               interrupts = <24 4>;
+                               interrupts = <24 4 2>;
                                status = "disabled";
                        };
                };
                usb0: ohci@00a00000 {
                        compatible = "atmel,at91rm9200-ohci", "usb-ohci";
                        reg = <0x00a00000 0x100000>;
-                       interrupts = <29 4>;
+                       interrupts = <29 4 2>;
                        status = "disabled";
                };
        };
index 7dbccaf199f7e0844bdeb3ee8cf789d8543f0a6f..bafa8806fc17293e3bddc28aff5b4829f677c178 100644 (file)
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <2>;
+                               #interrupt-cells = <3>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                reg = <0xfffff000 0x200>;
+                               atmel,external-irqs = <31>;
                        };
 
                        ramc0: ramc@ffffe400 {
@@ -78,7 +79,7 @@
                        pit: timer@fffffd30 {
                                compatible = "atmel,at91sam9260-pit";
                                reg = <0xfffffd30 0xf>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                        };
 
 
                        tcb0: timer@fff7c000 {
                                compatible = "atmel,at91rm9200-tcb";
                                reg = <0xfff7c000 0x100>;
-                               interrupts = <18 4>;
+                               interrupts = <18 4 0>;
                        };
 
                        tcb1: timer@fffd4000 {
                                compatible = "atmel,at91rm9200-tcb";
                                reg = <0xfffd4000 0x100>;
-                               interrupts = <18 4>;
+                               interrupts = <18 4 0>;
                        };
 
                        dma: dma-controller@ffffec00 {
                                compatible = "atmel,at91sam9g45-dma";
                                reg = <0xffffec00 0x200>;
-                               interrupts = <21 4>;
+                               interrupts = <21 4 0>;
                        };
 
                        pioA: gpio@fffff200 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff200 0x100>;
-                               interrupts = <2 4>;
+                               interrupts = <2 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioB: gpio@fffff400 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff400 0x100>;
-                               interrupts = <3 4>;
+                               interrupts = <3 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioC: gpio@fffff600 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff600 0x100>;
-                               interrupts = <4 4>;
+                               interrupts = <4 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioD: gpio@fffff800 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffff800 0x100>;
-                               interrupts = <5 4>;
+                               interrupts = <5 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioE: gpio@fffffa00 {
                                compatible = "atmel,at91rm9200-gpio";
                                reg = <0xfffffa00 0x100>;
-                               interrupts = <5 4>;
+                               interrupts = <5 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        dbgu: serial@ffffee00 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xffffee00 0x200>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                                status = "disabled";
                        };
 
                        usart0: serial@fff8c000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff8c000 0x200>;
-                               interrupts = <7 4>;
+                               interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@fff90000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff90000 0x200>;
-                               interrupts = <8 4>;
+                               interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@fff94000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff94000 0x200>;
-                               interrupts = <9 4>;
+                               interrupts = <9 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart3: serial@fff98000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfff98000 0x200>;
-                               interrupts = <10 4>;
+                               interrupts = <10 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@fffbc000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xfffbc000 0x100>;
-                               interrupts = <25 4>;
+                               interrupts = <25 4 3>;
                                status = "disabled";
                        };
 
                        adc0: adc@fffb0000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xfffb0000 0x100>;
-                               interrupts = <20 4>;
+                               interrupts = <20 4 0>;
                                atmel,adc-use-external-triggers;
                                atmel,adc-channels-used = <0xff>;
                                atmel,adc-vref = <3300>;
                usb0: ohci@00700000 {
                        compatible = "atmel,at91rm9200-ohci", "usb-ohci";
                        reg = <0x00700000 0x100000>;
-                       interrupts = <22 4>;
+                       interrupts = <22 4 2>;
                        status = "disabled";
                };
 
                usb1: ehci@00800000 {
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00800000 0x100000>;
-                       interrupts = <22 4>;
+                       interrupts = <22 4 2>;
                        status = "disabled";
                };
        };
index cb84de791b5ab9906e66e9664fcc80b4ae314b6e..bfac0dfc332c7d10bc3fe2f87458ec728c48b885 100644 (file)
@@ -50,7 +50,7 @@
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <2>;
+                               #interrupt-cells = <3>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                reg = <0xfffff000 0x200>;
@@ -74,7 +74,7 @@
                        pit: timer@fffffe30 {
                                compatible = "atmel,at91sam9260-pit";
                                reg = <0xfffffe30 0xf>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                        };
 
                        shdwc@fffffe10 {
                        tcb0: timer@f8008000 {
                                compatible = "atmel,at91sam9x5-tcb";
                                reg = <0xf8008000 0x100>;
-                               interrupts = <17 4>;
+                               interrupts = <17 4 0>;
                        };
 
                        tcb1: timer@f800c000 {
                                compatible = "atmel,at91sam9x5-tcb";
                                reg = <0xf800c000 0x100>;
-                               interrupts = <17 4>;
+                               interrupts = <17 4 0>;
                        };
 
                        dma: dma-controller@ffffec00 {
                                compatible = "atmel,at91sam9g45-dma";
                                reg = <0xffffec00 0x200>;
-                               interrupts = <20 4>;
+                               interrupts = <20 4 0>;
                        };
 
                        pioA: gpio@fffff400 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff400 0x100>;
-                               interrupts = <2 4>;
+                               interrupts = <2 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioB: gpio@fffff600 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff600 0x100>;
-                               interrupts = <2 4>;
+                               interrupts = <2 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioC: gpio@fffff800 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff800 0x100>;
-                               interrupts = <3 4>;
+                               interrupts = <3 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioD: gpio@fffffa00 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffffa00 0x100>;
-                               interrupts = <3 4>;
+                               interrupts = <3 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                                status = "disabled";
                        };
 
                        usart0: serial@f801c000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf801c000 0x4000>;
-                               interrupts = <5 4>;
+                               interrupts = <5 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@f8020000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf8020000 0x4000>;
-                               interrupts = <6 4>;
+                               interrupts = <6 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@f8024000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf8024000 0x4000>;
-                               interrupts = <7 4>;
+                               interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart3: serial@f8028000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf8028000 0x4000>;
-                               interrupts = <8 4>;
+                               interrupts = <8 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                usb0: ohci@00500000 {
                        compatible = "atmel,at91rm9200-ohci", "usb-ohci";
                        reg = <0x00500000 0x00100000>;
-                       interrupts = <22 4>;
+                       interrupts = <22 4 2>;
                        status = "disabled";
                };
        };
index 6b3ef4339ae7030eff85882a89f04d29ea346c21..4a18c393b1360f490c9796f3c598d349338ed2f5 100644 (file)
                        ranges;
 
                        aic: interrupt-controller@fffff000 {
-                               #interrupt-cells = <2>;
+                               #interrupt-cells = <3>;
                                compatible = "atmel,at91rm9200-aic";
                                interrupt-controller;
                                reg = <0xfffff000 0x200>;
+                               atmel,external-irqs = <31>;
                        };
 
                        ramc0: ramc@ffffe800 {
                        pit: timer@fffffe30 {
                                compatible = "atmel,at91sam9260-pit";
                                reg = <0xfffffe30 0xf>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                        };
 
                        tcb0: timer@f8008000 {
                                compatible = "atmel,at91sam9x5-tcb";
                                reg = <0xf8008000 0x100>;
-                               interrupts = <17 4>;
+                               interrupts = <17 4 0>;
                        };
 
                        tcb1: timer@f800c000 {
                                compatible = "atmel,at91sam9x5-tcb";
                                reg = <0xf800c000 0x100>;
-                               interrupts = <17 4>;
+                               interrupts = <17 4 0>;
                        };
 
                        dma0: dma-controller@ffffec00 {
                                compatible = "atmel,at91sam9g45-dma";
                                reg = <0xffffec00 0x200>;
-                               interrupts = <20 4>;
+                               interrupts = <20 4 0>;
                        };
 
                        dma1: dma-controller@ffffee00 {
                                compatible = "atmel,at91sam9g45-dma";
                                reg = <0xffffee00 0x200>;
-                               interrupts = <21 4>;
+                               interrupts = <21 4 0>;
                        };
 
                        pioA: gpio@fffff400 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff400 0x100>;
-                               interrupts = <2 4>;
+                               interrupts = <2 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioB: gpio@fffff600 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff600 0x100>;
-                               interrupts = <2 4>;
+                               interrupts = <2 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioC: gpio@fffff800 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffff800 0x100>;
-                               interrupts = <3 4>;
+                               interrupts = <3 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        pioD: gpio@fffffa00 {
                                compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                reg = <0xfffffa00 0x100>;
-                               interrupts = <3 4>;
+                               interrupts = <3 4 1>;
                                #gpio-cells = <2>;
                                gpio-controller;
                                interrupt-controller;
                        dbgu: serial@fffff200 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xfffff200 0x200>;
-                               interrupts = <1 4>;
+                               interrupts = <1 4 7>;
                                status = "disabled";
                        };
 
                        usart0: serial@f801c000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf801c000 0x200>;
-                               interrupts = <5 4>;
+                               interrupts = <5 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart1: serial@f8020000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf8020000 0x200>;
-                               interrupts = <6 4>;
+                               interrupts = <6 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        usart2: serial@f8024000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf8024000 0x200>;
-                               interrupts = <7 4>;
+                               interrupts = <7 4 5>;
                                atmel,use-dma-rx;
                                atmel,use-dma-tx;
                                status = "disabled";
                        macb0: ethernet@f802c000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xf802c000 0x100>;
-                               interrupts = <24 4>;
+                               interrupts = <24 4 3>;
                                status = "disabled";
                        };
 
                        macb1: ethernet@f8030000 {
                                compatible = "cdns,at32ap7000-macb", "cdns,macb";
                                reg = <0xf8030000 0x100>;
-                               interrupts = <27 4>;
+                               interrupts = <27 4 3>;
                                status = "disabled";
                        };
 
                        adc0: adc@f804c000 {
                                compatible = "atmel,at91sam9260-adc";
                                reg = <0xf804c000 0x100>;
-                               interrupts = <19 4>;
+                               interrupts = <19 4 0>;
                                atmel,adc-use-external;
                                atmel,adc-channels-used = <0xffff>;
                                atmel,adc-vref = <3300>;
                usb0: ohci@00600000 {
                        compatible = "atmel,at91rm9200-ohci", "usb-ohci";
                        reg = <0x00600000 0x100000>;
-                       interrupts = <22 4>;
+                       interrupts = <22 4 2>;
                        status = "disabled";
                };
 
                usb1: ehci@00700000 {
                        compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
                        reg = <0x00700000 0x100000>;
-                       interrupts = <22 4>;
+                       interrupts = <22 4 2>;
                        status = "disabled";
                };
        };
index 4ad5160018cb522922201b3dfebf9c0462b6ef85..3180a9c588b921d21ac9cea8b28e1c91b634686b 100644 (file)
@@ -48,7 +48,7 @@
                };
 
                rtc@80154000 {
-                       compatible = "stericsson,db8500-rtc";
+                       compatible = "arm,rtc-pl031", "arm,primecell";
                        reg = <0x80154000 0x1000>;
                        interrupts = <0 18 0x4>;
                };
@@ -60,7 +60,7 @@
                        interrupts = <0 119 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <0>;
@@ -73,7 +73,7 @@
                        interrupts = <0 120 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <1>;
@@ -86,7 +86,7 @@
                        interrupts = <0 121 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <2>;
@@ -99,7 +99,7 @@
                        interrupts = <0 122 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <3>;
                        interrupts = <0 123 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <4>;
                        interrupts = <0 124 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <5>;
                        interrupts = <0 125 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <6>;
                        interrupts = <0 126 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <7>;
                        interrupts = <0 127 0x4>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
-                       supports-sleepmode;
+                       st,supports-sleepmode;
                        gpio-controller;
                        #gpio-cells = <2>;
                        gpio-bank = <8>;
 
                                // DB8500_REGULATOR_VAPE
                                db8500_vape_reg: db8500_vape {
+                                       regulator-compatible = "db8500_vape";
                                        regulator-name = "db8500-vape";
                                        regulator-always-on;
                                };
 
                                // DB8500_REGULATOR_VARM
                                db8500_varm_reg: db8500_varm {
+                                       regulator-compatible = "db8500_varm";
                                        regulator-name = "db8500-varm";
                                };
 
                                // DB8500_REGULATOR_VMODEM
                                db8500_vmodem_reg: db8500_vmodem {
+                                       regulator-compatible = "db8500_vmodem";
                                        regulator-name = "db8500-vmodem";
                                };
 
                                // DB8500_REGULATOR_VPLL
                                db8500_vpll_reg: db8500_vpll {
+                                       regulator-compatible = "db8500_vpll";
                                        regulator-name = "db8500-vpll";
                                };
 
                                // DB8500_REGULATOR_VSMPS1
                                db8500_vsmps1_reg: db8500_vsmps1 {
+                                       regulator-compatible = "db8500_vsmps1";
                                        regulator-name = "db8500-vsmps1";
                                };
 
                                // DB8500_REGULATOR_VSMPS2
                                db8500_vsmps2_reg: db8500_vsmps2 {
+                                       regulator-compatible = "db8500_vsmps2";
                                        regulator-name = "db8500-vsmps2";
                                };
 
                                // DB8500_REGULATOR_VSMPS3
                                db8500_vsmps3_reg: db8500_vsmps3 {
+                                       regulator-compatible = "db8500_vsmps3";
                                        regulator-name = "db8500-vsmps3";
                                };
 
                                // DB8500_REGULATOR_VRF1
                                db8500_vrf1_reg: db8500_vrf1 {
+                                       regulator-compatible = "db8500_vrf1";
                                        regulator-name = "db8500-vrf1";
                                };
 
                                // DB8500_REGULATOR_SWITCH_SVAMMDSP
                                db8500_sva_mmdsp_reg: db8500_sva_mmdsp {
+                                       regulator-compatible = "db8500_sva_mmdsp";
                                        regulator-name = "db8500-sva-mmdsp";
                                };
 
                                // DB8500_REGULATOR_SWITCH_SVAMMDSPRET
                                db8500_sva_mmdsp_ret_reg: db8500_sva_mmdsp_ret {
+                                       regulator-compatible = "db8500_sva_mmdsp_ret";
                                        regulator-name = "db8500-sva-mmdsp-ret";
                                };
 
                                // DB8500_REGULATOR_SWITCH_SVAPIPE
                                db8500_sva_pipe_reg: db8500_sva_pipe {
+                                       regulator-compatible = "db8500_sva_pipe";
                                        regulator-name = "db8500_sva_pipe";
                                };
 
                                // DB8500_REGULATOR_SWITCH_SIAMMDSP
                                db8500_sia_mmdsp_reg: db8500_sia_mmdsp {
+                                       regulator-compatible = "db8500_sia_mmdsp";
                                        regulator-name = "db8500_sia_mmdsp";
                                };
 
 
                                // DB8500_REGULATOR_SWITCH_SIAPIPE
                                db8500_sia_pipe_reg: db8500_sia_pipe {
+                                       regulator-compatible = "db8500_sia_pipe";
                                        regulator-name = "db8500-sia-pipe";
                                };
 
                                // DB8500_REGULATOR_SWITCH_SGA
                                db8500_sga_reg: db8500_sga {
+                                       regulator-compatible = "db8500_sga";
                                        regulator-name = "db8500-sga";
                                        vin-supply = <&db8500_vape_reg>;
                                };
 
                                // DB8500_REGULATOR_SWITCH_B2R2_MCDE
                                db8500_b2r2_mcde_reg: db8500_b2r2_mcde {
+                                       regulator-compatible = "db8500_b2r2_mcde";
                                        regulator-name = "db8500-b2r2-mcde";
                                        vin-supply = <&db8500_vape_reg>;
                                };
 
                                // DB8500_REGULATOR_SWITCH_ESRAM12
                                db8500_esram12_reg: db8500_esram12 {
+                                       regulator-compatible = "db8500_esram12";
                                        regulator-name = "db8500-esram12";
                                };
 
                                // DB8500_REGULATOR_SWITCH_ESRAM12RET
                                db8500_esram12_ret_reg: db8500_esram12_ret {
+                                       regulator-compatible = "db8500_esram12_ret";
                                        regulator-name = "db8500-esram12-ret";
                                };
 
                                // DB8500_REGULATOR_SWITCH_ESRAM34
                                db8500_esram34_reg: db8500_esram34 {
+                                       regulator-compatible = "db8500_esram34";
                                        regulator-name = "db8500-esram34";
                                };
 
                                // DB8500_REGULATOR_SWITCH_ESRAM34RET
                                db8500_esram34_ret_reg: db8500_esram34_ret {
+                                       regulator-compatible = "db8500_esram34_ret";
                                        regulator-name = "db8500-esram34-ret";
                                };
                        };
                                compatible = "stericsson,ab8500";
                                reg = <5>; /* mailbox 5 is i2c */
                                interrupts = <0 40 0x4>;
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+
+                               ab8500-rtc {
+                                       compatible = "stericsson,ab8500-rtc";
+                                       interrupts = <17 0x4
+                                                     18 0x4>;
+                                       interrupt-names = "60S", "ALARM";
+                               };
+
+                               ab8500-gpadc {
+                                       compatible = "stericsson,ab8500-gpadc";
+                                       interrupts = <32 0x4
+                                                     39 0x4>;
+                                       interrupt-names = "HW_CONV_END", "SW_CONV_END";
+                                       vddadc-supply = <&ab8500_ldo_tvout_reg>;
+                               };
+
+                               ab8500-usb {
+                                       compatible = "stericsson,ab8500-usb";
+                                       interrupts = < 90 0x4
+                                                      96 0x4
+                                                      14 0x4
+                                                      15 0x4
+                                                      79 0x4
+                                                      74 0x4
+                                                      75 0x4>;
+                                       interrupt-names = "ID_WAKEUP_R",
+                                                         "ID_WAKEUP_F",
+                                                         "VBUS_DET_F",
+                                                         "VBUS_DET_R",
+                                                         "USB_LINK_STATUS",
+                                                         "USB_ADP_PROBE_PLUG",
+                                                         "USB_ADP_PROBE_UNPLUG";
+                                       vddulpivio18-supply = <&ab8500_ldo_initcore_reg>;
+                                       v-ape-supply = <&db8500_vape_reg>;
+                                       musb_1v8-supply = <&db8500_vsmps2_reg>;
+                               };
+
+                               ab8500-ponkey {
+                                       compatible = "stericsson,ab8500-ponkey";
+                                       interrupts = <6 0x4
+                                                     7 0x4>;
+                                       interrupt-names = "ONKEY_DBF", "ONKEY_DBR";
+                               };
+
+                               ab8500-sysctrl {
+                                       compatible = "stericsson,ab8500-sysctrl";
+                               };
+
+                               ab8500-pwm {
+                                       compatible = "stericsson,ab8500-pwm";
+                               };
+
+                               ab8500-debugfs {
+                                       compatible = "stericsson,ab8500-debug";
+                               };
 
                                ab8500-regulators {
                                        compatible = "stericsson,ab8500-regulator";
 
                                        // supplies to the display/camera
                                        ab8500_ldo_aux1_reg: ab8500_ldo_aux1 {
+                                               regulator-compatible = "ab8500_ldo_aux1";
                                                regulator-name = "V-DISPLAY";
                                                regulator-min-microvolt = <2500000>;
                                                regulator-max-microvolt = <2900000>;
 
                                        // supplies to the on-board eMMC
                                        ab8500_ldo_aux2_reg: ab8500_ldo_aux2 {
+                                               regulator-compatible = "ab8500_ldo_aux2";
                                                regulator-name = "V-eMMC1";
                                                regulator-min-microvolt = <1100000>;
                                                regulator-max-microvolt = <3300000>;
 
                                        // supply for VAUX3; SDcard slots
                                        ab8500_ldo_aux3_reg: ab8500_ldo_aux3 {
+                                               regulator-compatible = "ab8500_ldo_aux3";
                                                regulator-name = "V-MMC-SD";
                                                regulator-min-microvolt = <1100000>;
                                                regulator-max-microvolt = <3300000>;
 
                                        // supply for v-intcore12; VINTCORE12 LDO
                                        ab8500_ldo_initcore_reg: ab8500_ldo_initcore {
+                                               regulator-compatible = "ab8500_ldo_initcore";
                                                regulator-name = "V-INTCORE";
                                        };
 
                                        // supply for tvout; gpadc; TVOUT LDO
                                        ab8500_ldo_tvout_reg: ab8500_ldo_tvout {
+                                               regulator-compatible = "ab8500_ldo_tvout";
                                                regulator-name = "V-TVOUT";
                                        };
 
                                        // supply for ab8500-usb; USB LDO
                                        ab8500_ldo_usb_reg: ab8500_ldo_usb {
+                                               regulator-compatible = "ab8500_ldo_usb";
                                                regulator-name = "dummy";
                                        };
 
                                        // supply for ab8500-vaudio; VAUDIO LDO
                                        ab8500_ldo_audio_reg: ab8500_ldo_audio {
+                                               regulator-compatible = "ab8500_ldo_audio";
                                                regulator-name = "V-AUD";
                                        };
 
                                        // supply for v-anamic1 VAMic1-LDO
                                        ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 {
+                                               regulator-compatible = "ab8500_ldo_anamic1";
                                                regulator-name = "V-AMIC1";
                                        };
 
                                        // supply for v-amic2; VAMIC2 LDO; reuse constants for AMIC1
                                        ab8500_ldo_amamic2_reg: ab8500_ldo_amamic2 {
+                                               regulator-compatible = "ab8500_ldo_amamic2";
                                                regulator-name = "V-AMIC2";
                                        };
 
                                        // supply for v-dmic; VDMIC LDO
                                        ab8500_ldo_dmic_reg: ab8500_ldo_dmic {
+                                               regulator-compatible = "ab8500_ldo_dmic";
                                                regulator-name = "V-DMIC";
                                        };
 
                                        // supply for U8500 CSI/DSI; VANA LDO
                                        ab8500_ldo_ana_reg: ab8500_ldo_ana {
+                                               regulator-compatible = "ab8500_ldo_ana";
                                                regulator-name = "V-CSI/DSI";
                                        };
                                };
diff --git a/arch/arm/boot/dts/ea3250.dts b/arch/arm/boot/dts/ea3250.dts
new file mode 100644 (file)
index 0000000..d79b28d
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Embedded Artists LPC3250 board
+ *
+ * Copyright 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "lpc32xx.dtsi"
+
+/ {
+       model = "Embedded Artists LPC3250 board based on NXP LPC3250";
+       compatible = "ea,ea3250", "nxp,lpc3250";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       memory {
+               device_type = "memory";
+               reg = <0 0x4000000>;
+       };
+
+       ahb {
+               mac: ethernet@31060000 {
+                       phy-mode = "rmii";
+                       use-iram;
+               };
+
+               /* Here, choose exactly one from: ohci, usbd */
+               ohci@31020000 {
+                       transceiver = <&isp1301>;
+                       status = "okay";
+               };
+
+/*
+               usbd@31020000 {
+                       transceiver = <&isp1301>;
+                       status = "okay";
+               };
+*/
+
+               /* 128MB Flash via SLC NAND controller */
+               slc: flash@20020000 {
+                       status = "okay";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       nxp,wdr-clks = <14>;
+                       nxp,wwidth = <260000000>;
+                       nxp,whold = <104000000>;
+                       nxp,wsetup = <200000000>;
+                       nxp,rdr-clks = <14>;
+                       nxp,rwidth = <34666666>;
+                       nxp,rhold = <104000000>;
+                       nxp,rsetup = <200000000>;
+                       nand-on-flash-bbt;
+                       gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+                       mtd0@00000000 {
+                               label = "ea3250-boot";
+                               reg = <0x00000000 0x00080000>;
+                               read-only;
+                       };
+
+                       mtd1@00080000 {
+                               label = "ea3250-uboot";
+                               reg = <0x00080000 0x000c0000>;
+                               read-only;
+                       };
+
+                       mtd2@00140000 {
+                               label = "ea3250-kernel";
+                               reg = <0x00140000 0x00400000>;
+                       };
+
+                       mtd3@00540000 {
+                               label = "ea3250-rootfs";
+                               reg = <0x00540000 0x07ac0000>;
+                       };
+               };
+
+               apb {
+                       uart5: serial@40090000 {
+                               status = "okay";
+                       };
+
+                       uart3: serial@40080000 {
+                               status = "okay";
+                       };
+
+                       uart6: serial@40098000 {
+                               status = "okay";
+                       };
+
+                       i2c1: i2c@400A0000 {
+                               clock-frequency = <100000>;
+
+                               eeprom@50 {
+                                       compatible = "at,24c256";
+                                       reg = <0x50>;
+                               };
+
+                               eeprom@57 {
+                                       compatible = "at,24c64";
+                                       reg = <0x57>;
+                               };
+
+                               uda1380: uda1380@18 {
+                                       compatible = "nxp,uda1380";
+                                       reg = <0x18>;
+                                       power-gpio = <&gpio 0x59 0>;
+                                       reset-gpio = <&gpio 0x51 0>;
+                                       dac-clk = "wspll";
+                               };
+
+                               pca9532: pca9532@60 {
+                                       compatible = "nxp,pca9532";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       reg = <0x60>;
+                               };
+                       };
+
+                       i2c2: i2c@400A8000 {
+                               clock-frequency = <100000>;
+                       };
+
+                       i2cusb: i2c@31020300 {
+                               clock-frequency = <100000>;
+
+                               isp1301: usb-transceiver@2d {
+                                       compatible = "nxp,isp1301";
+                                       reg = <0x2d>;
+                               };
+                       };
+
+                       sd@20098000 {
+                               wp-gpios = <&pca9532 5 0>;
+                               cd-gpios = <&pca9532 4 0>;
+                               cd-inverted;
+                               bus-width = <4>;
+                               status = "okay";
+                       };
+               };
+
+               fab {
+                       uart1: serial@40014000 {
+                               status = "okay";
+                       };
+
+                       /* 3-axis accelerometer X,Y,Z (or AD-IN instead of Z) */
+                       adc@40048000 {
+                               status = "okay";
+                       };
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               autorepeat;
+               button@21 {
+                       label = "GPIO Key UP";
+                       linux,code = <103>;
+                       gpios = <&gpio 4 1 0>; /* GPI_P3 1 */
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/evk-pro3.dts b/arch/arm/boot/dts/evk-pro3.dts
new file mode 100644 (file)
index 0000000..b7354e6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * evk-pro3.dts - Device Tree file for Telit EVK-PRO3 with Telit GE863-PRO3
+ *
+ * Copyright (C) 2012 Telit,
+ *               2012 Fabio Porcedda <fabio.porcedda@gmail.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/dts-v1/;
+
+/include/ "ge863-pro3.dtsi"
+
+/ {
+       model = "Telit EVK-PRO3 for Telit GE863-PRO3";
+       compatible = "telit,evk-pro3", "atmel,at91sam9260", "atmel,at91sam9";
+
+       ahb {
+               apb {
+                       macb0: ethernet@fffc4000 {
+                               phy-mode = "rmii";
+                               status = "okay";
+                       };
+
+                       usb1: gadget@fffa4000 {
+                               atmel,vbus-gpio = <&pioC 5 0>;
+                               status = "okay";
+                       };
+               };
+
+               usb0: ohci@00500000 {
+                       num-ports = <2>;
+                       status = "okay";
+               };
+       };
+
+       i2c@0 {
+               status = "okay";
+       };
+
+};
\ No newline at end of file
index b8c476384eef92d8ec7d44eac1d5e275a84e4de1..0c49caa099786b4c247831da4b539da7a32711ab 100644 (file)
        i2c@138D0000 {
                status = "disabled";
        };
+
+       spi_0: spi@13920000 {
+               status = "disabled";
+       };
+
+       spi_1: spi@13930000 {
+               status = "disabled";
+       };
+
+       spi_2: spi@13940000 {
+               status = "disabled";
+       };
 };
index 27afc8e535ca69618de7a10c9fabb5a35983f2a4..1beccc8f14ff948c622a6af681141221139ba021 100644 (file)
        i2c@138D0000 {
                status = "disabled";
        };
+
+       spi_0: spi@13920000 {
+               status = "disabled";
+       };
+
+       spi_1: spi@13930000 {
+               status = "disabled";
+       };
+
+       spi_2: spi@13940000 {
+               gpios = <&gpc1 1 5 3 0>,
+                       <&gpc1 3 5 3 0>,
+                       <&gpc1 4 5 3 0>;
+
+               w25x80@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "w25x80";
+                       reg = <0>;
+                       spi-max-frequency = <1000000>;
+
+                       controller-data {
+                               cs-gpio = <&gpc1 2 1 0 3>;
+                               samsung,spi-feedback-delay = <0>;
+                       };
+
+                       partition@0 {
+                               label = "U-Boot";
+                               reg = <0x0 0x40000>;
+                               read-only;
+                       };
+
+                       partition@40000 {
+                               label = "Kernel";
+                               reg = <0x40000 0xc0000>;
+                       };
+               };
+       };
 };
index a1dd2ee83753d0740c4d774dd03b556b2614f309..02891fe876e43bbbdb947aae28840baa7f9fa860 100644 (file)
        compatible = "samsung,exynos4210";
        interrupt-parent = <&gic>;
 
+       aliases {
+               spi0 = &spi_0;
+               spi1 = &spi_1;
+               spi2 = &spi_2;
+       };
+
        gic:interrupt-controller@10490000 {
                compatible = "arm,cortex-a9-gic";
                #interrupt-cells = <3>;
                reg = <0x10490000 0x1000>, <0x10480000 0x100>;
        };
 
+       combiner:interrupt-controller@10440000 {
+               compatible = "samsung,exynos4210-combiner";
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               reg = <0x10440000 0x1000>;
+               interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                            <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                            <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                            <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
+       };
+
        watchdog@10060000 {
                compatible = "samsung,s3c2410-wdt";
                reg = <0x10060000 0x100>;
                interrupts = <0 65 0>;
        };
 
+       spi_0: spi@13920000 {
+               compatible = "samsung,exynos4210-spi";
+               reg = <0x13920000 0x100>;
+               interrupts = <0 66 0>;
+               tx-dma-channel = <&pdma0 7>; /* preliminary */
+               rx-dma-channel = <&pdma0 6>; /* preliminary */
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       spi_1: spi@13930000 {
+               compatible = "samsung,exynos4210-spi";
+               reg = <0x13930000 0x100>;
+               interrupts = <0 67 0>;
+               tx-dma-channel = <&pdma1 7>; /* preliminary */
+               rx-dma-channel = <&pdma1 6>; /* preliminary */
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       spi_2: spi@13940000 {
+               compatible = "samsung,exynos4210-spi";
+               reg = <0x13940000 0x100>;
+               interrupts = <0 68 0>;
+               tx-dma-channel = <&pdma0 9>; /* preliminary */
+               rx-dma-channel = <&pdma0 8>; /* preliminary */
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
        amba {
                #address-cells = <1>;
                #size-cells = <1>;
index 49945cc1bc7df3795b71812c67f98c3ec88e5e72..8a5e348793c765e8caf189004f8c04848378206d 100644 (file)
        i2c@12CD0000 {
                status = "disabled";
        };
+
+       spi_0: spi@12d20000 {
+               status = "disabled";
+       };
+
+       spi_1: spi@12d30000 {
+               gpios = <&gpa2 4 2 3 0>,
+                       <&gpa2 6 2 3 0>,
+                       <&gpa2 7 2 3 0>;
+
+               w25q80bw@0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "w25x80";
+                       reg = <0>;
+                       spi-max-frequency = <1000000>;
+
+                       controller-data {
+                               cs-gpio = <&gpa2 5 1 0 3>;
+                               samsung,spi-feedback-delay = <0>;
+                       };
+
+                       partition@0 {
+                               label = "U-Boot";
+                               reg = <0x0 0x40000>;
+                               read-only;
+                       };
+
+                       partition@40000 {
+                               label = "Kernel";
+                               reg = <0x40000 0xc0000>;
+                       };
+               };
+       };
+
+       spi_2: spi@12d40000 {
+               status = "disabled";
+       };
 };
index 4272b2949228ba2e4ea9d7ebb7bc2285fd9bb19b..004aaa8d123cd66fed607c7c45ebc5827cd018dd 100644 (file)
        compatible = "samsung,exynos5250";
        interrupt-parent = <&gic>;
 
+       aliases {
+               spi0 = &spi_0;
+               spi1 = &spi_1;
+               spi2 = &spi_2;
+       };
+
        gic:interrupt-controller@10481000 {
                compatible = "arm,cortex-a9-gic";
                #interrupt-cells = <3>;
                #size-cells = <0>;
        };
 
+       spi_0: spi@12d20000 {
+               compatible = "samsung,exynos4210-spi";
+               reg = <0x12d20000 0x100>;
+               interrupts = <0 66 0>;
+               tx-dma-channel = <&pdma0 5>; /* preliminary */
+               rx-dma-channel = <&pdma0 4>; /* preliminary */
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       spi_1: spi@12d30000 {
+               compatible = "samsung,exynos4210-spi";
+               reg = <0x12d30000 0x100>;
+               interrupts = <0 67 0>;
+               tx-dma-channel = <&pdma1 5>; /* preliminary */
+               rx-dma-channel = <&pdma1 4>; /* preliminary */
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
+       spi_2: spi@12d40000 {
+               compatible = "samsung,exynos4210-spi";
+               reg = <0x12d40000 0x100>;
+               interrupts = <0 68 0>;
+               tx-dma-channel = <&pdma0 7>; /* preliminary */
+               rx-dma-channel = <&pdma0 6>; /* preliminary */
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
        amba {
                #address-cells = <1>;
                #size-cells = <1>;
diff --git a/arch/arm/boot/dts/ge863-pro3.dtsi b/arch/arm/boot/dts/ge863-pro3.dtsi
new file mode 100644 (file)
index 0000000..17136fc
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * ge863_pro3.dtsi - Device Tree file for Telit GE863-PRO3
+ *
+ * Copyright (C) 2012 Telit,
+ *               2012 Fabio Porcedda <fabio.porcedda@gmail.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "at91sam9260.dtsi"
+
+/ {
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               main_clock: clock@0 {
+                       compatible = "atmel,osc", "fixed-clock";
+                       clock-frequency = <6000000>;
+               };
+       };
+
+       ahb {
+               apb {
+                       dbgu: serial@fffff200 {
+                               status = "okay";
+                       };
+               };
+
+               nand0: nand@40000000 {
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "soft";
+                       nand-on-flash-bbt;
+                       status = "okay";
+
+                       boot@0 {
+                               label = "boot";
+                               reg = <0x0 0x7c0000>;
+                       };
+
+                       root@07c0000 {
+                               label = "root";
+                               reg = <0x7c0000 0x7840000>;
+                       };
+               };
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200 root=ubi0:rootfs ubi.mtd=1 rootfstype=ubifs";
+       };
+};
index 70bffa929b659b43ab67de96d00663475ed89a4a..e3486f486b405cfb74cb1dcbe41f808a49f5e658 100644 (file)
 
        apb@80000000 {
                apbh@80000000 {
+                       gpmi-nand@8000c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&gpmi_pins_a &gpmi_pins_fixup>;
+                               status = "okay";
+                       };
+
                        ssp0: ssp@80010000 {
                                compatible = "fsl,imx23-mmc";
                                pinctrl-names = "default";
-                               pinctrl-0 = <&mmc0_8bit_pins_a &mmc0_pins_fixup>;
-                               bus-width = <8>;
+                               pinctrl-0 = <&mmc0_4bit_pins_a &mmc0_pins_fixup>;
+                               bus-width = <4>;
                                wp-gpios = <&gpio1 30 0>;
+                               vmmc-supply = <&reg_vddio_sd0>;
+                               status = "okay";
+                       };
+
+                       pinctrl@80018000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hog_pins_a>;
+
+                               hog_pins_a: hog-gpios@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x1123 /* MX23_PAD_LCD_RESET__GPIO_1_18 */
+                                               0x11d3 /* MX23_PAD_PWM3__GPIO_1_29 */
+                                               0x11e3 /* MX23_PAD_PWM4__GPIO_1_30 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+                       };
+
+                       lcdif@80030000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&lcdif_24bit_pins_a>;
+                               panel-enable-gpios = <&gpio1 18 0>;
                                status = "okay";
                        };
                };
 
                apbx@80040000 {
+                       pwm: pwm@80064000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pwm2_pins_a>;
+                               status = "okay";
+                       };
+
+                       auart0: serial@8006c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart0_pins_a>;
+                               status = "okay";
+                       };
+
                        duart: serial@80070000 {
                                pinctrl-names = "default";
                                pinctrl-0 = <&duart_pins_a>;
                        };
                };
        };
+
+       regulators {
+               compatible = "simple-bus";
+
+               reg_vddio_sd0: vddio-sd0 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "vddio-sd0";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       gpio = <&gpio1 29 0>;
+               };
+       };
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 2 5000000>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <6>;
+       };
 };
diff --git a/arch/arm/boot/dts/imx23-olinuxino.dts b/arch/arm/boot/dts/imx23-olinuxino.dts
new file mode 100644 (file)
index 0000000..20912b1
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Fabio Estevam <fabio.estevam@freescale.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "imx23.dtsi"
+
+/ {
+       model = "i.MX23 Olinuxino Low Cost Board";
+       compatible = "olimex,imx23-olinuxino", "fsl,imx23";
+
+       memory {
+               reg = <0x40000000 0x04000000>;
+       };
+
+       apb@80000000 {
+               apbh@80000000 {
+                       ssp0: ssp@80010000 {
+                               compatible = "fsl,imx23-mmc";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&mmc0_4bit_pins_a &mmc0_pins_fixup>;
+                               bus-width = <4>;
+                               status = "okay";
+                       };
+               };
+
+               apbx@80040000 {
+                       duart: serial@80070000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&duart_pins_a>;
+                               status = "okay";
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx23-stmp378x_devb.dts b/arch/arm/boot/dts/imx23-stmp378x_devb.dts
new file mode 100644 (file)
index 0000000..757a327
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "imx23.dtsi"
+
+/ {
+       model = "Freescale STMP378x Development Board";
+       compatible = "fsl,stmp378x-devb", "fsl,imx23";
+
+       memory {
+               reg = <0x40000000 0x04000000>;
+       };
+
+       apb@80000000 {
+               apbh@80000000 {
+                       ssp0: ssp@80010000 {
+                               compatible = "fsl,imx23-mmc";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&mmc0_4bit_pins_a &mmc0_pins_fixup>;
+                               bus-width = <4>;
+                               wp-gpios = <&gpio1 30 0>;
+                               vmmc-supply = <&reg_vddio_sd0>;
+                               status = "okay";
+                       };
+
+                       pinctrl@80018000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hog_pins_a>;
+
+                               hog_pins_a: hog-gpios@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x11d3 /* MX23_PAD_PWM3__GPIO_1_29 */
+                                               0x11e3 /* MX23_PAD_PWM4__GPIO_1_30 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+                       };
+               };
+
+               apbx@80040000 {
+                       auart0: serial@8006c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart0_pins_a>;
+                               status = "okay";
+                       };
+
+                       duart: serial@80070000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&duart_pins_a>;
+                               status = "okay";
+                       };
+               };
+       };
+
+       regulators {
+               compatible = "simple-bus";
+
+               reg_vddio_sd0: vddio-sd0 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "vddio-sd0";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       gpio = <&gpio1 29 0>;
+               };
+       };
+};
index 8c5f9994f3fc226265c83e3d6fe44952319b1725..a874dbfb5ae69da5d6771c75d9605ca3bbbcbcaa 100644 (file)
@@ -18,6 +18,8 @@
                gpio0 = &gpio0;
                gpio1 = &gpio1;
                gpio2 = &gpio2;
+               serial0 = &auart0;
+               serial1 = &auart1;
        };
 
        cpus {
                                status = "disabled";
                        };
 
-                       bch@8000a000 {
-                               reg = <0x8000a000 2000>;
-                               status = "disabled";
-                       };
-
-                       gpmi@8000c000 {
-                               reg = <0x8000c000 2000>;
+                       gpmi-nand@8000c000 {
+                               compatible = "fsl,imx23-gpmi-nand";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               reg = <0x8000c000 2000>, <0x8000a000 2000>;
+                               reg-names = "gpmi-nand", "bch";
+                               interrupts = <13>, <56>;
+                               interrupt-names = "gpmi-dma", "bch";
+                               fsl,gpmi-dma-channel = <4>;
                                status = "disabled";
                        };
 
 
                                duart_pins_a: duart@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x11a2 0x11b2>;
+                                       fsl,pinmux-ids = <
+                                               0x11a2 /* MX23_PAD_PWM0__DUART_RX */
+                                               0x11b2 /* MX23_PAD_PWM1__DUART_TX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               auart0_pins_a: auart0@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x01c0 /* MX23_PAD_AUART1_RX__AUART1_RX */
+                                               0x01d0 /* MX23_PAD_AUART1_TX__AUART1_TX */
+                                               0x01a0 /* MX23_PAD_AUART1_CTS__AUART1_CTS */
+                                               0x01b0 /* MX23_PAD_AUART1_RTS__AUART1_RTS */
+                                       >;
                                        fsl,drive-strength = <0>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <0>;
                                };
 
+                               gpmi_pins_a: gpmi-nand@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x0000 /* MX23_PAD_GPMI_D00__GPMI_D00 */
+                                               0x0010 /* MX23_PAD_GPMI_D01__GPMI_D01 */
+                                               0x0020 /* MX23_PAD_GPMI_D02__GPMI_D02 */
+                                               0x0030 /* MX23_PAD_GPMI_D03__GPMI_D03 */
+                                               0x0040 /* MX23_PAD_GPMI_D04__GPMI_D04 */
+                                               0x0050 /* MX23_PAD_GPMI_D05__GPMI_D05 */
+                                               0x0060 /* MX23_PAD_GPMI_D06__GPMI_D06 */
+                                               0x0070 /* MX23_PAD_GPMI_D07__GPMI_D07 */
+                                               0x0100 /* MX23_PAD_GPMI_CLE__GPMI_CLE */
+                                               0x0110 /* MX23_PAD_GPMI_ALE__GPMI_ALE */
+                                               0x0130 /* MX23_PAD_GPMI_RDY0__GPMI_RDY0 */
+                                               0x0140 /* MX23_PAD_GPMI_RDY1__GPMI_RDY1 */
+                                               0x0170 /* MX23_PAD_GPMI_WPN__GPMI_WPN */
+                                               0x0180 /* MX23_PAD_GPMI_WRN__GPMI_WRN */
+                                               0x0190 /* MX23_PAD_GPMI_RDN__GPMI_RDN */
+                                               0x21b0 /* MX23_PAD_GPMI_CE1N__GPMI_CE1N */
+                                               0x21c0 /* MX23_PAD_GPMI_CE0N__GPMI_CE0N */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               gpmi_pins_fixup: gpmi-pins-fixup {
+                                       fsl,pinmux-ids = <
+                                               0x0170 /* MX23_PAD_GPMI_WPN__GPMI_WPN */
+                                               0x0180 /* MX23_PAD_GPMI_WRN__GPMI_WRN */
+                                               0x0190 /* MX23_PAD_GPMI_RDN__GPMI_RDN */
+                                       >;
+                                       fsl,drive-strength = <2>;
+                               };
+
+                               mmc0_4bit_pins_a: mmc0-4bit@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x2020 /* MX23_PAD_SSP1_DATA0__SSP1_DATA0 */
+                                               0x2030 /* MX23_PAD_SSP1_DATA1__SSP1_DATA1 */
+                                               0x2040 /* MX23_PAD_SSP1_DATA2__SSP1_DATA2 */
+                                               0x2050 /* MX23_PAD_SSP1_DATA3__SSP1_DATA3 */
+                                               0x2000 /* MX23_PAD_SSP1_CMD__SSP1_CMD */
+                                               0x2010 /* MX23_PAD_SSP1_DETECT__SSP1_DETECT */
+                                               0x2060 /* MX23_PAD_SSP1_SCK__SSP1_SCK */
+                                       >;
+                                       fsl,drive-strength = <1>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <1>;
+                               };
+
                                mmc0_8bit_pins_a: mmc0-8bit@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x2020 0x2030 0x2040
-                                               0x2050 0x0082 0x0092 0x00a2
-                                               0x00b2 0x2000 0x2010 0x2060>;
+                                       fsl,pinmux-ids = <
+                                               0x2020 /* MX23_PAD_SSP1_DATA0__SSP1_DATA0 */
+                                               0x2030 /* MX23_PAD_SSP1_DATA1__SSP1_DATA1 */
+                                               0x2040 /* MX23_PAD_SSP1_DATA2__SSP1_DATA2 */
+                                               0x2050 /* MX23_PAD_SSP1_DATA3__SSP1_DATA3 */
+                                               0x0082 /* MX23_PAD_GPMI_D08__SSP1_DATA4 */
+                                               0x0092 /* MX23_PAD_GPMI_D09__SSP1_DATA5 */
+                                               0x00a2 /* MX23_PAD_GPMI_D10__SSP1_DATA6 */
+                                               0x00b2 /* MX23_PAD_GPMI_D11__SSP1_DATA7 */
+                                               0x2000 /* MX23_PAD_SSP1_CMD__SSP1_CMD */
+                                               0x2010 /* MX23_PAD_SSP1_DETECT__SSP1_DETECT */
+                                               0x2060 /* MX23_PAD_SSP1_SCK__SSP1_SCK */
+                                       >;
                                        fsl,drive-strength = <1>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <1>;
                                };
 
                                mmc0_pins_fixup: mmc0-pins-fixup {
-                                       fsl,pinmux-ids = <0x2010 0x2060>;
+                                       fsl,pinmux-ids = <
+                                               0x2010 /* MX23_PAD_SSP1_DETECT__SSP1_DETECT */
+                                               0x2060 /* MX23_PAD_SSP1_SCK__SSP1_SCK */
+                                       >;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               pwm2_pins_a: pwm2@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x11c0 /* MX23_PAD_PWM2__PWM2 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               lcdif_24bit_pins_a: lcdif-24bit@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x1000 /* MX23_PAD_LCD_D00__LCD_D0 */
+                                               0x1010 /* MX23_PAD_LCD_D01__LCD_D1 */
+                                               0x1020 /* MX23_PAD_LCD_D02__LCD_D2 */
+                                               0x1030 /* MX23_PAD_LCD_D03__LCD_D3 */
+                                               0x1040 /* MX23_PAD_LCD_D04__LCD_D4 */
+                                               0x1050 /* MX23_PAD_LCD_D05__LCD_D5 */
+                                               0x1060 /* MX23_PAD_LCD_D06__LCD_D6 */
+                                               0x1070 /* MX23_PAD_LCD_D07__LCD_D7 */
+                                               0x1080 /* MX23_PAD_LCD_D08__LCD_D8 */
+                                               0x1090 /* MX23_PAD_LCD_D09__LCD_D9 */
+                                               0x10a0 /* MX23_PAD_LCD_D10__LCD_D10 */
+                                               0x10b0 /* MX23_PAD_LCD_D11__LCD_D11 */
+                                               0x10c0 /* MX23_PAD_LCD_D12__LCD_D12 */
+                                               0x10d0 /* MX23_PAD_LCD_D13__LCD_D13 */
+                                               0x10e0 /* MX23_PAD_LCD_D14__LCD_D14 */
+                                               0x10f0 /* MX23_PAD_LCD_D15__LCD_D15 */
+                                               0x1100 /* MX23_PAD_LCD_D16__LCD_D16 */
+                                               0x1110 /* MX23_PAD_LCD_D17__LCD_D17 */
+                                               0x0081 /* MX23_PAD_GPMI_D08__LCD_D18 */
+                                               0x0091 /* MX23_PAD_GPMI_D09__LCD_D19 */
+                                               0x00a1 /* MX23_PAD_GPMI_D10__LCD_D20 */
+                                               0x00b1 /* MX23_PAD_GPMI_D11__LCD_D21 */
+                                               0x00c1 /* MX23_PAD_GPMI_D12__LCD_D22 */
+                                               0x00d1 /* MX23_PAD_GPMI_D13__LCD_D23 */
+                                               0x1160 /* MX23_PAD_LCD_DOTCK__LCD_DOTCK */
+                                               0x1170 /* MX23_PAD_LCD_ENABLE__LCD_ENABLE */
+                                               0x1180 /* MX23_PAD_LCD_HSYNC__LCD_HSYNC */
+                                               0x1190 /* MX23_PAD_LCD_VSYNC__LCD_VSYNC */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
                                        fsl,pull-up = <0>;
                                };
                        };
                        };
 
                        lcdif@80030000 {
+                               compatible = "fsl,imx23-lcdif";
                                reg = <0x80030000 2000>;
+                               interrupts = <46 45>;
                                status = "disabled";
                        };
 
                        };
 
                        rtc@8005c000 {
+                               compatible = "fsl,imx23-rtc", "fsl,stmp3xxx-rtc";
                                reg = <0x8005c000 2000>;
-                               status = "disabled";
+                               interrupts = <22>;
                        };
 
-                       pwm@80064000 {
+                       pwm: pwm@80064000 {
+                               compatible = "fsl,imx23-pwm";
                                reg = <0x80064000 2000>;
+                               #pwm-cells = <2>;
+                               fsl,pwm-number = <5>;
                                status = "disabled";
                        };
 
                        };
 
                        auart0: serial@8006c000 {
+                               compatible = "fsl,imx23-auart";
                                reg = <0x8006c000 0x2000>;
+                               interrupts = <24 25 23>;
                                status = "disabled";
                        };
 
                        auart1: serial@8006e000 {
+                               compatible = "fsl,imx23-auart";
                                reg = <0x8006e000 0x2000>;
+                               interrupts = <59 60 58>;
                                status = "disabled";
                        };
 
diff --git a/arch/arm/boot/dts/imx27-3ds.dts b/arch/arm/boot/dts/imx27-3ds.dts
new file mode 100644 (file)
index 0000000..d3f8296
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "imx27.dtsi"
+
+/ {
+       model = "mx27_3ds";
+       compatible = "freescale,imx27-3ds", "fsl,imx27";
+
+       memory {
+               reg = <0x0 0x0>;
+       };
+
+       soc {
+               aipi@10000000 { /* aipi */
+
+                       wdog@10002000 {
+                               status = "okay";
+                       };
+
+                       uart@1000a000 {
+                               fsl,uart-has-rtscts;
+                               status = "okay";
+                       };
+
+                       fec@1002b000 {
+                               status = "okay";
+                       };
+               };
+       };
+
+};
index 386c769c38d179dcb090bba33af5aeb6ec2f0a0a..00bae3aad5ab601f7a21adf4da8539aa48880781 100644 (file)
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio2: gpio@10015100 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio3: gpio@10015200 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio4: gpio@10015300 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio5: gpio@10015400 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio6: gpio@10015500 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        cspi3: cspi@10017000 {
diff --git a/arch/arm/boot/dts/imx28-apx4devkit.dts b/arch/arm/boot/dts/imx28-apx4devkit.dts
new file mode 100644 (file)
index 0000000..b383417
--- /dev/null
@@ -0,0 +1,198 @@
+/dts-v1/;
+/include/ "imx28.dtsi"
+
+/ {
+       model = "Bluegiga APX4 Development Kit";
+       compatible = "bluegiga,apx4devkit", "fsl,imx28";
+
+       memory {
+               reg = <0x40000000 0x04000000>;
+       };
+
+       apb@80000000 {
+               apbh@80000000 {
+                       gpmi-nand@8000c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&gpmi_pins_a &gpmi_status_cfg>;
+                               status = "okay";
+                       };
+
+                       ssp0: ssp@80010000 {
+                               compatible = "fsl,imx28-mmc";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&mmc0_4bit_pins_a &mmc0_sck_cfg>;
+                               bus-width = <4>;
+                               status = "okay";
+                       };
+
+                       ssp2: ssp@80014000 {
+                               compatible = "fsl,imx28-mmc";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&mmc2_4bit_pins_apx4 &mmc2_sck_cfg_apx4>;
+                               bus-width = <4>;
+                               status = "okay";
+                       };
+
+                       pinctrl@80018000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hog_pins_a>;
+
+                               hog_pins_a: hog-gpios@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x0113 /* MX28_PAD_GPMI_CE1N__GPIO_0_17 */
+                                               0x0153 /* MX28_PAD_GPMI_RDY1__GPIO_0_21 */
+                                               0x2123 /* MX28_PAD_SSP2_MISO__GPIO_2_18 */
+                                               0x2131 /* MX28_PAD_SSP2_SS0__GPIO_2_19 */
+                                               0x31c3 /* MX28_PAD_PWM3__GPIO_3_28 */
+                                               0x31e3 /* MX28_PAD_LCD_RESET__GPIO_3_30 */
+                                               0x4143 /* MX28_PAD_JTAG_RTCK__GPIO_4_20 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               lcdif_pins_apx4: lcdif-apx4@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x1181 /* MX28_PAD_LCD_RD_E__LCD_VSYNC */
+                                               0x1191 /* MX28_PAD_LCD_WR_RWN__LCD_HSYNC */
+                                               0x11a1 /* MX28_PAD_LCD_RS__LCD_DOTCLK */
+                                               0x11b1 /* MX28_PAD_LCD_CS__LCD_ENABLE */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               mmc2_4bit_pins_apx4: mmc2-4bit-apx4@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x2041 /* MX28_PAD_SSP0_DATA4__SSP2_D0 */
+                                               0x2051 /* MX28_PAD_SSP0_DATA5__SSP2_D3 */
+                                               0x2061 /* MX28_PAD_SSP0_DATA6__SSP2_CMD */
+                                               0x2071 /* MX28_PAD_SSP0_DATA7__SSP2_SCK */
+                                               0x2141 /* MX28_PAD_SSP2_SS1__SSP2_D1 */
+                                               0x2151 /* MX28_PAD_SSP2_SS2__SSP2_D2 */
+                                       >;
+                                       fsl,drive-strength = <1>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <1>;
+                               };
+
+                               mmc2_sck_cfg_apx4: mmc2-sck-cfg-apx4 {
+                                       fsl,pinmux-ids = <
+                                               0x2071 /* MX28_PAD_SSP0_DATA7__SSP2_SCK */
+                                       >;
+                                       fsl,drive-strength = <2>;
+                                       fsl,pull-up = <0>;
+                               };
+                       };
+
+                       lcdif@80030000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&lcdif_24bit_pins_a
+                                            &lcdif_pins_apx4>;
+                               status = "okay";
+                       };
+               };
+
+               apbx@80040000 {
+                       saif0: saif@80042000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&saif0_pins_a>;
+                               status = "okay";
+                       };
+
+                       saif1: saif@80046000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&saif1_pins_a>;
+                               fsl,saif-master = <&saif0>;
+                               status = "okay";
+                       };
+
+                       i2c0: i2c@80058000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&i2c0_pins_a>;
+                               status = "okay";
+
+                               sgtl5000: codec@0a {
+                                       compatible = "fsl,sgtl5000";
+                                       reg = <0x0a>;
+                                       VDDA-supply = <&reg_3p3v>;
+                                       VDDIO-supply = <&reg_3p3v>;
+
+                               };
+
+                               pcf8563: rtc@51 {
+                                       compatible = "phg,pcf8563";
+                                       reg = <0x51>;
+                               };
+                       };
+
+                       duart: serial@80074000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&duart_pins_a>;
+                               status = "okay";
+                       };
+
+                       auart0: serial@8006a000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart0_pins_a>;
+                               status = "okay";
+                       };
+
+                       auart1: serial@8006c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart1_2pins_a>;
+                               status = "okay";
+                       };
+
+                       auart2: serial@8006e000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart2_2pins_a>;
+                               status = "okay";
+                       };
+               };
+       };
+
+       ahb@80080000 {
+               mac0: ethernet@800f0000 {
+                       phy-mode = "rmii";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mac0_pins_a>;
+                       status = "okay";
+               };
+       };
+
+       regulators {
+               compatible = "simple-bus";
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
+       };
+
+       sound {
+               compatible = "bluegiga,apx4devkit-sgtl5000",
+                            "fsl,mxs-audio-sgtl5000";
+               model = "apx4devkit-sgtl5000";
+               saif-controllers = <&saif0 &saif1>;
+               audio-codec = <&sgtl5000>;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user {
+                       label = "Heartbeat";
+                       gpios = <&gpio3 28 0>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx28-cfa10036.dts b/arch/arm/boot/dts/imx28-cfa10036.dts
new file mode 100644 (file)
index 0000000..c03a577
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 Free Electrons
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "imx28.dtsi"
+
+/ {
+       model = "Crystalfontz CFA-10036 Board";
+       compatible = "crystalfontz,cfa10036", "fsl,imx28";
+
+       memory {
+               reg = <0x40000000 0x08000000>;
+       };
+
+       apb@80000000 {
+               apbh@80000000 {
+                       ssp0: ssp@80010000 {
+                               compatible = "fsl,imx28-mmc";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&mmc0_4bit_pins_a
+                                       &mmc0_cd_cfg &mmc0_sck_cfg>;
+                               bus-width = <4>;
+                               status = "okay";
+                       };
+               };
+
+               apbx@80040000 {
+                       duart: serial@80074000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&duart_pins_b>;
+                               status = "okay";
+                       };
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               power {
+                       gpios = <&gpio3 4 1>;
+                       default-state = "on";
+               };
+       };
+};
index ee520a529cb4a6406385b72a3717d00c8c791fbf..773c0e84d1fb54cb1724c03e0101b0053d483bee 100644 (file)
 
        apb@80000000 {
                apbh@80000000 {
+                       gpmi-nand@8000c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&gpmi_pins_a &gpmi_status_cfg
+                                            &gpmi_pins_evk>;
+                               status = "okay";
+                       };
+
                        ssp0: ssp@80010000 {
                                compatible = "fsl,imx28-mmc";
                                pinctrl-names = "default";
@@ -29,6 +36,7 @@
                                        &mmc0_cd_cfg &mmc0_sck_cfg>;
                                bus-width = <8>;
                                wp-gpios = <&gpio2 12 0>;
+                               vmmc-supply = <&reg_vddio_sd0>;
                                status = "okay";
                        };
 
                                compatible = "fsl,imx28-mmc";
                                bus-width = <8>;
                                wp-gpios = <&gpio0 28 0>;
+                       };
+
+                       pinctrl@80018000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hog_pins_a>;
+
+                               hog_pins_a: hog-gpios@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x20d3 /* MX28_PAD_SSP1_CMD__GPIO_2_13 */
+                                               0x20f3 /* MX28_PAD_SSP1_DATA3__GPIO_2_15 */
+                                               0x40d3 /* MX28_PAD_ENET0_RX_CLK__GPIO_4_13 */
+                                               0x20c3 /* MX28_PAD_SSP1_SCK__GPIO_2_12 */
+                                               0x31c3 /* MX28_PAD_PWM3__GPIO_3_28 */
+                                               0x31e3 /* MX28_PAD_LCD_RESET__GPIO_3_30 */
+                                               0x3053 /* MX28_PAD_AUART1_TX__GPIO_3_5 */
+                                               0x3083 /* MX28_PAD_AUART2_RX__GPIO_3_8 */
+                                               0x3093 /* MX28_PAD_AUART2_TX__GPIO_3_9 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               gpmi_pins_evk: gpmi-nand-evk@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x0110 /* MX28_PAD_GPMI_CE1N__GPMI_CE1N */
+                                               0x0150 /* MX28_PAD_GPMI_RDY1__GPMI_READY1 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               lcdif_pins_evk: lcdif-evk@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x1181 /* MX28_PAD_LCD_RD_E__LCD_VSYNC */
+                                               0x1191 /* MX28_PAD_LCD_WR_RWN__LCD_HSYNC */
+                                               0x11a1 /* MX28_PAD_LCD_RS__LCD_DOTCLK */
+                                               0x11b1 /* MX28_PAD_LCD_CS__LCD_ENABLE */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+                       };
+
+                       lcdif@80030000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&lcdif_24bit_pins_a
+                                            &lcdif_pins_evk>;
+                               panel-enable-gpios = <&gpio3 30 0>;
+                               status = "okay";
+                       };
+
+                       can0: can@80032000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&can0_pins_a>;
+                               status = "okay";
+                       };
+
+                       can1: can@80034000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&can1_pins_a>;
                                status = "okay";
                        };
                };
                                };
                        };
 
+                       pwm: pwm@80064000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pwm2_pins_a>;
+                               status = "okay";
+                       };
+
                        duart: serial@80074000 {
                                pinctrl-names = "default";
                                pinctrl-0 = <&duart_pins_a>;
                                status = "okay";
                        };
+
+                       auart0: serial@8006a000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart0_pins_a>;
+                               status = "okay";
+                       };
+
+                       auart3: serial@80070000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart3_pins_a>;
+                               status = "okay";
+                       };
+
+                       usbphy0: usbphy@8007c000 {
+                               status = "okay";
+                       };
+
+                       usbphy1: usbphy@8007e000 {
+                               status = "okay";
+                       };
                };
        };
 
        ahb@80080000 {
+               usb0: usb@80080000 {
+                       vbus-supply = <&reg_usb0_vbus>;
+                       status = "okay";
+               };
+
+               usb1: usb@80090000 {
+                       vbus-supply = <&reg_usb1_vbus>;
+                       status = "okay";
+               };
+
                mac0: ethernet@800f0000 {
                        phy-mode = "rmii";
                        pinctrl-names = "default";
                        pinctrl-0 = <&mac0_pins_a>;
+                       phy-supply = <&reg_fec_3v3>;
+                       phy-reset-gpios = <&gpio4 13 0>;
+                       phy-reset-duration = <100>;
                        status = "okay";
                };
 
                        regulator-max-microvolt = <3300000>;
                        regulator-always-on;
                };
+
+               reg_vddio_sd0: vddio-sd0 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "vddio-sd0";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       gpio = <&gpio3 28 0>;
+               };
+
+               reg_fec_3v3: fec-3v3 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "fec-3v3";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       gpio = <&gpio2 15 0>;
+               };
+
+               reg_usb0_vbus: usb0_vbus {
+                       compatible = "regulator-fixed";
+                       regulator-name = "usb0_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio3 9 0>;
+                       enable-active-high;
+               };
+
+               reg_usb1_vbus: usb1_vbus {
+                       compatible = "regulator-fixed";
+                       regulator-name = "usb1_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio3 8 0>;
+                       enable-active-high;
+               };
        };
 
        sound {
                saif-controllers = <&saif0 &saif1>;
                audio-codec = <&sgtl5000>;
        };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user {
+                       label = "Heartbeat";
+                       gpios = <&gpio3 5 0>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 2 5000000>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <6>;
+       };
 };
diff --git a/arch/arm/boot/dts/imx28-m28evk.dts b/arch/arm/boot/dts/imx28-m28evk.dts
new file mode 100644 (file)
index 0000000..183a3fd
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "imx28.dtsi"
+
+/ {
+       model = "DENX M28EVK";
+       compatible = "denx,m28evk", "fsl,imx28";
+
+       memory {
+               reg = <0x40000000 0x08000000>;
+       };
+
+       apb@80000000 {
+               apbh@80000000 {
+                       gpmi-nand@8000c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&gpmi_pins_a &gpmi_status_cfg>;
+                               status = "okay";
+
+                               partition@0 {
+                                       label = "bootloader";
+                                       reg = <0x00000000 0x00300000>;
+                                       read-only;
+                               };
+
+                               partition@1 {
+                                       label = "environment";
+                                       reg = <0x00300000 0x00080000>;
+                               };
+
+                               partition@2 {
+                                       label = "redundant-environment";
+                                       reg = <0x00380000 0x00080000>;
+                               };
+
+                               partition@3 {
+                                       label = "kernel";
+                                       reg = <0x00400000 0x00400000>;
+                               };
+
+                               partition@4 {
+                                       label = "filesystem";
+                                       reg = <0x00800000 0x0f800000>;
+                               };
+                       };
+
+                       ssp0: ssp@80010000 {
+                               compatible = "fsl,imx28-mmc";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&mmc0_8bit_pins_a
+                                            &mmc0_cd_cfg
+                                            &mmc0_sck_cfg>;
+                               bus-width = <8>;
+                               wp-gpios = <&gpio3 10 1>;
+                               status = "okay";
+                       };
+
+                       pinctrl@80018000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hog_pins_a>;
+
+                               hog_pins_a: hog-gpios@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x30a3 /* MX28_PAD_AUART2_CTS__GPIO_3_10 */
+                                               0x30b3 /* MX28_PAD_AUART2_RTS__GPIO_3_11 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               lcdif_pins_m28: lcdif-m28@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x11e0 /* MX28_PAD_LCD_DOTCLK__LCD_DOTCLK */
+                                               0x11f0 /* MX28_PAD_LCD_ENABLE__LCD_ENABLE */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+                       };
+
+                       lcdif@80030000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&lcdif_24bit_pins_a
+                                            &lcdif_pins_m28>;
+                               status = "okay";
+                       };
+
+                       can0: can@80032000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&can0_pins_a>;
+                               status = "okay";
+                       };
+
+                       can1: can@80034000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&can1_pins_a>;
+                               status = "okay";
+                       };
+               };
+
+               apbx@80040000 {
+                       saif0: saif@80042000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&saif0_pins_a>;
+                               status = "okay";
+                       };
+
+                       saif1: saif@80046000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&saif1_pins_a>;
+                               fsl,saif-master = <&saif0>;
+                               status = "okay";
+                       };
+
+                       i2c0: i2c@80058000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&i2c0_pins_a>;
+                               status = "okay";
+
+                               sgtl5000: codec@0a {
+                                       compatible = "fsl,sgtl5000";
+                                       reg = <0x0a>;
+                                       VDDA-supply = <&reg_3p3v>;
+                                       VDDIO-supply = <&reg_3p3v>;
+
+                               };
+
+                               eeprom: eeprom@51 {
+                                       compatible = "atmel,24c128";
+                                       reg = <0x51>;
+                                       pagesize = <32>;
+                               };
+
+                               rtc: rtc@68 {
+                                       compatible = "stm,mt41t62";
+                                       reg = <0x68>;
+                               };
+                       };
+
+                       duart: serial@80074000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&duart_pins_a>;
+                               status = "okay";
+                       };
+
+                       auart0: serial@8006a000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart0_2pins_a>;
+                               status = "okay";
+                       };
+
+                       auart3: serial@80070000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart3_pins_a>;
+                               status = "okay";
+                       };
+               };
+       };
+
+       ahb@80080000 {
+               mac0: ethernet@800f0000 {
+                       phy-mode = "rmii";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mac0_pins_a>;
+                       phy-reset-gpios = <&gpio3 11 0>;
+                       status = "okay";
+               };
+
+               mac1: ethernet@800f4000 {
+                       phy-mode = "rmii";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mac1_pins_a>;
+                       status = "okay";
+               };
+       };
+
+       regulators {
+               compatible = "simple-bus";
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
+       };
+
+       sound {
+               compatible = "denx,m28evk-sgtl5000",
+                            "fsl,mxs-audio-sgtl5000";
+               model = "m28evk-sgtl5000";
+               saif-controllers = <&saif0 &saif1>;
+               audio-codec = <&sgtl5000>;
+       };
+};
diff --git a/arch/arm/boot/dts/imx28-tx28.dts b/arch/arm/boot/dts/imx28-tx28.dts
new file mode 100644 (file)
index 0000000..62bf767
--- /dev/null
@@ -0,0 +1,97 @@
+/dts-v1/;
+/include/ "imx28.dtsi"
+
+/ {
+       model = "Ka-Ro electronics TX28 module";
+       compatible = "karo,tx28", "fsl,imx28";
+
+       memory {
+               reg = <0x40000000 0x08000000>;
+       };
+
+       apb@80000000 {
+               apbh@80000000 {
+                       ssp0: ssp@80010000 {
+                               compatible = "fsl,imx28-mmc";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&mmc0_4bit_pins_a
+                                            &mmc0_cd_cfg
+                                            &mmc0_sck_cfg>;
+                               bus-width = <4>;
+                               status = "okay";
+                       };
+
+                       pinctrl@80018000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&hog_pins_a>;
+
+                               hog_pins_a: hog-gpios@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x40a3 /* MX28_PAD_ENET0_RXD3__GPIO_4_10 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+                       };
+               };
+
+               apbx@80040000 {
+                       i2c0: i2c@80058000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&i2c0_pins_a>;
+                               status = "okay";
+
+                               ds1339: rtc@68 {
+                                       compatible = "mxim,ds1339";
+                                       reg = <0x68>;
+                               };
+                       };
+
+                       pwm: pwm@80064000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pwm0_pins_a>;
+                               status = "okay";
+                       };
+
+                       duart: serial@80074000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&duart_4pins_a>;
+                               status = "okay";
+                       };
+
+                       auart1: serial@8006c000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&auart1_pins_a>;
+                               status = "okay";
+                       };
+               };
+       };
+
+       ahb@80080000 {
+               mac0: ethernet@800f0000 {
+                       phy-mode = "rmii";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mac0_pins_a>;
+                       status = "okay";
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user {
+                       label = "Heartbeat";
+                       gpios = <&gpio4 10 0>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       backlight {
+               compatible = "pwm-backlight";
+               pwms = <&pwm 0 5000000>;
+               brightness-levels = <0 4 8 16 32 64 128 255>;
+               default-brightness-level = <6>;
+       };
+};
index 4634cb861a597d115b5f6dab784da3a616c81b01..915db89e364431450347e69e93c9e73bb6b59108 100644 (file)
                gpio4 = &gpio4;
                saif0 = &saif0;
                saif1 = &saif1;
+               serial0 = &auart0;
+               serial1 = &auart1;
+               serial2 = &auart2;
+               serial3 = &auart3;
+               serial4 = &auart4;
        };
 
        cpus {
                                status = "disabled";
                        };
 
-                       bch@8000a000 {
-                               reg = <0x8000a000 2000>;
-                               interrupts = <41>;
-                               status = "disabled";
-                       };
-
-                       gpmi@8000c000 {
-                               reg = <0x8000c000 2000>;
-                               interrupts = <42 88>;
+                       gpmi-nand@8000c000 {
+                               compatible = "fsl,imx28-gpmi-nand";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               reg = <0x8000c000 2000>, <0x8000a000 2000>;
+                               reg-names = "gpmi-nand", "bch";
+                               interrupts = <88>, <41>;
+                               interrupt-names = "gpmi-dma", "bch";
+                               fsl,gpmi-dma-channel = <4>;
                                status = "disabled";
                        };
 
 
                                duart_pins_a: duart@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x3102 0x3112>;
+                                       fsl,pinmux-ids = <
+                                               0x3102 /* MX28_PAD_PWM0__DUART_RX */
+                                               0x3112 /* MX28_PAD_PWM1__DUART_TX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               duart_pins_b: duart@1 {
+                                       reg = <1>;
+                                       fsl,pinmux-ids = <
+                                               0x3022 /* MX28_PAD_AUART0_CTS__DUART_RX */
+                                               0x3032 /* MX28_PAD_AUART0_RTS__DUART_TX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               duart_4pins_a: duart-4pins@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x3022 /* MX28_PAD_AUART0_CTS__DUART_RX */
+                                               0x3032 /* MX28_PAD_AUART0_RTS__DUART_TX */
+                                               0x3002 /* MX28_PAD_AUART0_RX__DUART_CTS */
+                                               0x3012 /* MX28_PAD_AUART0_TX__DUART_RTS */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               gpmi_pins_a: gpmi-nand@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x0000 /* MX28_PAD_GPMI_D00__GPMI_D0 */
+                                               0x0010 /* MX28_PAD_GPMI_D01__GPMI_D1 */
+                                               0x0020 /* MX28_PAD_GPMI_D02__GPMI_D2 */
+                                               0x0030 /* MX28_PAD_GPMI_D03__GPMI_D3 */
+                                               0x0040 /* MX28_PAD_GPMI_D04__GPMI_D4 */
+                                               0x0050 /* MX28_PAD_GPMI_D05__GPMI_D5 */
+                                               0x0060 /* MX28_PAD_GPMI_D06__GPMI_D6 */
+                                               0x0070 /* MX28_PAD_GPMI_D07__GPMI_D7 */
+                                               0x0100 /* MX28_PAD_GPMI_CE0N__GPMI_CE0N */
+                                               0x0140 /* MX28_PAD_GPMI_RDY0__GPMI_READY0 */
+                                               0x0180 /* MX28_PAD_GPMI_RDN__GPMI_RDN */
+                                               0x0190 /* MX28_PAD_GPMI_WRN__GPMI_WRN */
+                                               0x01a0 /* MX28_PAD_GPMI_ALE__GPMI_ALE */
+                                               0x01b0 /* MX28_PAD_GPMI_CLE__GPMI_CLE */
+                                               0x01c0 /* MX28_PAD_GPMI_RESETN__GPMI_RESETN */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               gpmi_status_cfg: gpmi-status-cfg {
+                                       fsl,pinmux-ids = <
+                                               0x0180 /* MX28_PAD_GPMI_RDN__GPMI_RDN */
+                                               0x0190 /* MX28_PAD_GPMI_WRN__GPMI_WRN */
+                                               0x01c0 /* MX28_PAD_GPMI_RESETN__GPMI_RESETN */
+                                       >;
+                                       fsl,drive-strength = <2>;
+                               };
+
+                               auart0_pins_a: auart0@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x3000 /* MX28_PAD_AUART0_RX__AUART0_RX */
+                                               0x3010 /* MX28_PAD_AUART0_TX__AUART0_TX */
+                                               0x3020 /* MX28_PAD_AUART0_CTS__AUART0_CTS */
+                                               0x3030 /* MX28_PAD_AUART0_RTS__AUART0_RTS */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               auart0_2pins_a: auart0-2pins@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x3000 /* MX28_PAD_AUART0_RX__AUART0_RX */
+                                               0x3010 /* MX28_PAD_AUART0_TX__AUART0_TX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               auart1_pins_a: auart1@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x3040 /* MX28_PAD_AUART1_RX__AUART1_RX */
+                                               0x3050 /* MX28_PAD_AUART1_TX__AUART1_TX */
+                                               0x3060 /* MX28_PAD_AUART1_CTS__AUART1_CTS */
+                                               0x3070 /* MX28_PAD_AUART1_RTS__AUART1_RTS */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               auart1_2pins_a: auart1-2pins@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x3040 /* MX28_PAD_AUART1_RX__AUART1_RX */
+                                               0x3050 /* MX28_PAD_AUART1_TX__AUART1_TX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               auart2_2pins_a: auart2-2pins@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x2101 /* MX28_PAD_SSP2_SCK__AUART2_RX */
+                                               0x2111 /* MX28_PAD_SSP2_MOSI__AUART2_TX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               auart3_pins_a: auart3@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x30c0 /* MX28_PAD_AUART3_RX__AUART3_RX */
+                                               0x30d0 /* MX28_PAD_AUART3_TX__AUART3_TX */
+                                               0x30e0 /* MX28_PAD_AUART3_CTS__AUART3_CTS */
+                                               0x30f0 /* MX28_PAD_AUART3_RTS__AUART3_RTS */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               auart3_2pins_a: auart3-2pins@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x2121 /* MX28_PAD_SSP2_MISO__AUART3_RX */
+                                               0x2131 /* MX28_PAD_SSP2_SS0__AUART3_TX */
+                                       >;
                                        fsl,drive-strength = <0>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <0>;
 
                                mac0_pins_a: mac0@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x4000 0x4010 0x4020
-                                               0x4030 0x4040 0x4060 0x4070
-                                               0x4080 0x4100>;
+                                       fsl,pinmux-ids = <
+                                               0x4000 /* MX28_PAD_ENET0_MDC__ENET0_MDC */
+                                               0x4010 /* MX28_PAD_ENET0_MDIO__ENET0_MDIO */
+                                               0x4020 /* MX28_PAD_ENET0_RX_EN__ENET0_RX_EN */
+                                               0x4030 /* MX28_PAD_ENET0_RXD0__ENET0_RXD0 */
+                                               0x4040 /* MX28_PAD_ENET0_RXD1__ENET0_RXD1 */
+                                               0x4060 /* MX28_PAD_ENET0_TX_EN__ENET0_TX_EN */
+                                               0x4070 /* MX28_PAD_ENET0_TXD0__ENET0_TXD0 */
+                                               0x4080 /* MX28_PAD_ENET0_TXD1__ENET0_TXD1 */
+                                               0x4100 /* MX28_PAD_ENET_CLK__CLKCTRL_ENET */
+                                       >;
                                        fsl,drive-strength = <1>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <1>;
 
                                mac1_pins_a: mac1@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x40f1 0x4091 0x40a1
-                                               0x40e1 0x40b1 0x40c1>;
+                                       fsl,pinmux-ids = <
+                                               0x40f1 /* MX28_PAD_ENET0_CRS__ENET1_RX_EN */
+                                               0x4091 /* MX28_PAD_ENET0_RXD2__ENET1_RXD0 */
+                                               0x40a1 /* MX28_PAD_ENET0_RXD3__ENET1_RXD1 */
+                                               0x40e1 /* MX28_PAD_ENET0_COL__ENET1_TX_EN */
+                                               0x40b1 /* MX28_PAD_ENET0_TXD2__ENET1_TXD0 */
+                                               0x40c1 /* MX28_PAD_ENET0_TXD3__ENET1_TXD1 */
+                                       >;
                                        fsl,drive-strength = <1>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <1>;
 
                                mmc0_8bit_pins_a: mmc0-8bit@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x2000 0x2010 0x2020
-                                               0x2030 0x2040 0x2050 0x2060
-                                               0x2070 0x2080 0x2090 0x20a0>;
+                                       fsl,pinmux-ids = <
+                                               0x2000 /* MX28_PAD_SSP0_DATA0__SSP0_D0 */
+                                               0x2010 /* MX28_PAD_SSP0_DATA1__SSP0_D1 */
+                                               0x2020 /* MX28_PAD_SSP0_DATA2__SSP0_D2 */
+                                               0x2030 /* MX28_PAD_SSP0_DATA3__SSP0_D3 */
+                                               0x2040 /* MX28_PAD_SSP0_DATA4__SSP0_D4 */
+                                               0x2050 /* MX28_PAD_SSP0_DATA5__SSP0_D5 */
+                                               0x2060 /* MX28_PAD_SSP0_DATA6__SSP0_D6 */
+                                               0x2070 /* MX28_PAD_SSP0_DATA7__SSP0_D7 */
+                                               0x2080 /* MX28_PAD_SSP0_CMD__SSP0_CMD */
+                                               0x2090 /* MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT */
+                                               0x20a0 /* MX28_PAD_SSP0_SCK__SSP0_SCK */
+                                       >;
+                                       fsl,drive-strength = <1>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <1>;
+                               };
+
+                               mmc0_4bit_pins_a: mmc0-4bit@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x2000 /* MX28_PAD_SSP0_DATA0__SSP0_D0 */
+                                               0x2010 /* MX28_PAD_SSP0_DATA1__SSP0_D1 */
+                                               0x2020 /* MX28_PAD_SSP0_DATA2__SSP0_D2 */
+                                               0x2030 /* MX28_PAD_SSP0_DATA3__SSP0_D3 */
+                                               0x2080 /* MX28_PAD_SSP0_CMD__SSP0_CMD */
+                                               0x2090 /* MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT */
+                                               0x20a0 /* MX28_PAD_SSP0_SCK__SSP0_SCK */
+                                       >;
                                        fsl,drive-strength = <1>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <1>;
                                };
 
                                mmc0_cd_cfg: mmc0-cd-cfg {
-                                       fsl,pinmux-ids = <0x2090>;
+                                       fsl,pinmux-ids = <
+                                               0x2090 /* MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT */
+                                       >;
                                        fsl,pull-up = <0>;
                                };
 
                                mmc0_sck_cfg: mmc0-sck-cfg {
-                                       fsl,pinmux-ids = <0x20a0>;
+                                       fsl,pinmux-ids = <
+                                               0x20a0 /* MX28_PAD_SSP0_SCK__SSP0_SCK */
+                                       >;
                                        fsl,drive-strength = <2>;
                                        fsl,pull-up = <0>;
                                };
 
                                i2c0_pins_a: i2c0@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x3180 0x3190>;
+                                       fsl,pinmux-ids = <
+                                               0x3180 /* MX28_PAD_I2C0_SCL__I2C0_SCL */
+                                               0x3190 /* MX28_PAD_I2C0_SDA__I2C0_SDA */
+                                       >;
                                        fsl,drive-strength = <1>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <1>;
 
                                saif0_pins_a: saif0@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids =
-                                               <0x3140 0x3150 0x3160 0x3170>;
+                                       fsl,pinmux-ids = <
+                                               0x3140 /* MX28_PAD_SAIF0_MCLK__SAIF0_MCLK */
+                                               0x3150 /* MX28_PAD_SAIF0_LRCLK__SAIF0_LRCLK */
+                                               0x3160 /* MX28_PAD_SAIF0_BITCLK__SAIF0_BITCLK */
+                                               0x3170 /* MX28_PAD_SAIF0_SDATA0__SAIF0_SDATA0 */
+                                       >;
                                        fsl,drive-strength = <2>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <1>;
 
                                saif1_pins_a: saif1@0 {
                                        reg = <0>;
-                                       fsl,pinmux-ids = <0x31a0>;
+                                       fsl,pinmux-ids = <
+                                               0x31a0 /* MX28_PAD_SAIF1_SDATA0__SAIF1_SDATA0 */
+                                       >;
                                        fsl,drive-strength = <2>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <1>;
                                };
+
+                               pwm0_pins_a: pwm0@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x3100 /* MX28_PAD_PWM0__PWM_0 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               pwm2_pins_a: pwm2@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x3120 /* MX28_PAD_PWM2__PWM_2 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               lcdif_24bit_pins_a: lcdif-24bit@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x1000 /* MX28_PAD_LCD_D00__LCD_D0 */
+                                               0x1010 /* MX28_PAD_LCD_D01__LCD_D1 */
+                                               0x1020 /* MX28_PAD_LCD_D02__LCD_D2 */
+                                               0x1030 /* MX28_PAD_LCD_D03__LCD_D3 */
+                                               0x1040 /* MX28_PAD_LCD_D04__LCD_D4 */
+                                               0x1050 /* MX28_PAD_LCD_D05__LCD_D5 */
+                                               0x1060 /* MX28_PAD_LCD_D06__LCD_D6 */
+                                               0x1070 /* MX28_PAD_LCD_D07__LCD_D7 */
+                                               0x1080 /* MX28_PAD_LCD_D08__LCD_D8 */
+                                               0x1090 /* MX28_PAD_LCD_D09__LCD_D9 */
+                                               0x10a0 /* MX28_PAD_LCD_D10__LCD_D10 */
+                                               0x10b0 /* MX28_PAD_LCD_D11__LCD_D11 */
+                                               0x10c0 /* MX28_PAD_LCD_D12__LCD_D12 */
+                                               0x10d0 /* MX28_PAD_LCD_D13__LCD_D13 */
+                                               0x10e0 /* MX28_PAD_LCD_D14__LCD_D14 */
+                                               0x10f0 /* MX28_PAD_LCD_D15__LCD_D15 */
+                                               0x1100 /* MX28_PAD_LCD_D16__LCD_D16 */
+                                               0x1110 /* MX28_PAD_LCD_D17__LCD_D17 */
+                                               0x1120 /* MX28_PAD_LCD_D18__LCD_D18 */
+                                               0x1130 /* MX28_PAD_LCD_D19__LCD_D19 */
+                                               0x1140 /* MX28_PAD_LCD_D20__LCD_D20 */
+                                               0x1150 /* MX28_PAD_LCD_D21__LCD_D21 */
+                                               0x1160 /* MX28_PAD_LCD_D22__LCD_D22 */
+                                               0x1170 /* MX28_PAD_LCD_D23__LCD_D23 */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               can0_pins_a: can0@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x0161 /* MX28_PAD_GPMI_RDY2__CAN0_TX */
+                                               0x0171 /* MX28_PAD_GPMI_RDY3__CAN0_RX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
+
+                               can1_pins_a: can1@0 {
+                                       reg = <0>;
+                                       fsl,pinmux-ids = <
+                                               0x0121 /* MX28_PAD_GPMI_CE2N__CAN1_TX */
+                                               0x0131 /* MX28_PAD_GPMI_CE3N__CAN1_RX */
+                                       >;
+                                       fsl,drive-strength = <0>;
+                                       fsl,voltage = <1>;
+                                       fsl,pull-up = <0>;
+                               };
                        };
 
                        digctl@8001c000 {
                        };
 
                        lcdif@80030000 {
+                               compatible = "fsl,imx28-lcdif";
                                reg = <0x80030000 2000>;
                                interrupts = <38 86>;
                                status = "disabled";
                        };
 
                        can0: can@80032000 {
+                               compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan";
                                reg = <0x80032000 2000>;
                                interrupts = <8>;
                                status = "disabled";
                        };
 
                        can1: can@80034000 {
+                               compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan";
                                reg = <0x80034000 2000>;
                                interrupts = <9>;
                                status = "disabled";
                        };
 
                        rtc@80056000 {
+                               compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc";
                                reg = <0x80056000 2000>;
-                               interrupts = <28 29>;
-                               status = "disabled";
+                               interrupts = <29>;
                        };
 
                        i2c0: i2c@80058000 {
                                status = "disabled";
                        };
 
-                       pwm@80064000 {
+                       pwm: pwm@80064000 {
+                               compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
                                reg = <0x80064000 2000>;
+                               #pwm-cells = <2>;
+                               fsl,pwm-number = <8>;
                                status = "disabled";
                        };
 
                        };
 
                        auart0: serial@8006a000 {
+                               compatible = "fsl,imx28-auart", "fsl,imx23-auart";
                                reg = <0x8006a000 0x2000>;
                                interrupts = <112 70 71>;
                                status = "disabled";
                        };
 
                        auart1: serial@8006c000 {
+                               compatible = "fsl,imx28-auart", "fsl,imx23-auart";
                                reg = <0x8006c000 0x2000>;
                                interrupts = <113 72 73>;
                                status = "disabled";
                        };
 
                        auart2: serial@8006e000 {
+                               compatible = "fsl,imx28-auart", "fsl,imx23-auart";
                                reg = <0x8006e000 0x2000>;
                                interrupts = <114 74 75>;
                                status = "disabled";
                        };
 
                        auart3: serial@80070000 {
+                               compatible = "fsl,imx28-auart", "fsl,imx23-auart";
                                reg = <0x80070000 0x2000>;
                                interrupts = <115 76 77>;
                                status = "disabled";
                        };
 
                        auart4: serial@80072000 {
+                               compatible = "fsl,imx28-auart", "fsl,imx23-auart";
                                reg = <0x80072000 0x2000>;
                                interrupts = <116 78 79>;
                                status = "disabled";
                        };
 
                        usbphy0: usbphy@8007c000 {
+                               compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy";
                                reg = <0x8007c000 0x2000>;
                                status = "disabled";
                        };
 
                        usbphy1: usbphy@8007e000 {
+                               compatible = "fsl,imx28-usbphy", "fsl,imx23-usbphy";
                                reg = <0x8007e000 0x2000>;
                                status = "disabled";
                        };
                reg = <0x80080000 0x80000>;
                ranges;
 
-               usbctrl0: usbctrl@80080000 {
+               usb0: usb@80080000 {
+                       compatible = "fsl,imx28-usb", "fsl,imx27-usb";
                        reg = <0x80080000 0x10000>;
+                       interrupts = <93>;
+                       fsl,usbphy = <&usbphy0>;
                        status = "disabled";
                };
 
-               usbctrl1: usbctrl@80090000 {
+               usb1: usb@80090000 {
+                       compatible = "fsl,imx28-usb", "fsl,imx27-usb";
                        reg = <0x80090000 0x10000>;
+                       interrupts = <92>;
+                       fsl,usbphy = <&usbphy1>;
                        status = "disabled";
                };
 
diff --git a/arch/arm/boot/dts/imx31-bug.dts b/arch/arm/boot/dts/imx31-bug.dts
new file mode 100644 (file)
index 0000000..24731cb
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "imx31.dtsi"
+
+/ {
+       model = "Buglabs i.MX31 Bug 1.x";
+       compatible = "fsl,imx31-bug", "fsl,imx31";
+
+       memory {
+               reg = <0x80000000 0x8000000>; /* 128M */
+       };
+
+       soc {
+               aips@43f00000 { /* AIPS1 */
+                       uart5: serial@43fb4000 {
+                               fsl,uart-has-rtscts;
+                               status = "okay";
+                       };
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi
new file mode 100644 (file)
index 0000000..eef7099
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+       aliases {
+               serial0 = &uart1;
+               serial1 = &uart2;
+               serial2 = &uart3;
+               serial3 = &uart4;
+               serial4 = &uart5;
+       };
+
+       avic: avic-interrupt-controller@60000000 {
+               compatible = "fsl,imx31-avic", "fsl,avic";
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               reg = <0x60000000 0x100000>;
+       };
+
+       soc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               interrupt-parent = <&avic>;
+               ranges;
+
+               aips@43f00000 { /* AIPS1 */
+                       compatible = "fsl,aips-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x43f00000 0x100000>;
+                       ranges;
+
+                       uart1: serial@43f90000 {
+                               compatible = "fsl,imx31-uart", "fsl,imx21-uart";
+                               reg = <0x43f90000 0x4000>;
+                               interrupts = <45>;
+                               status = "disabled";
+                       };
+
+                       uart2: serial@43f94000 {
+                               compatible = "fsl,imx31-uart", "fsl,imx21-uart";
+                               reg = <0x43f94000 0x4000>;
+                               interrupts = <32>;
+                               status = "disabled";
+                       };
+
+                       uart4: serial@43fb0000 {
+                               compatible = "fsl,imx31-uart", "fsl,imx21-uart";
+                               reg = <0x43fb0000 0x4000>;
+                               interrupts = <46>;
+                               status = "disabled";
+                       };
+
+                       uart5: serial@43fb4000 {
+                               compatible = "fsl,imx31-uart", "fsl,imx21-uart";
+                               reg = <0x43fb4000 0x4000>;
+                               interrupts = <47>;
+                               status = "disabled";
+                       };
+               };
+
+               spba@50000000 {
+                       compatible = "fsl,spba-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x50000000 0x100000>;
+                       ranges;
+
+                       uart3: serial@5000c000 {
+                               compatible = "fsl,imx31-uart", "fsl,imx21-uart";
+                               reg = <0x5000c000 0x4000>;
+                               interrupts = <18>;
+                               status = "disabled";
+                       };
+               };
+       };
+};
index bfa65abe8ef29444f4a56ca88c7fa1fd05591a47..922adefdd29120d14e5c7456ddbf3d6144b26f11 100644 (file)
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio2: gpio@73f88000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio3: gpio@73f8c000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio4: gpio@73f90000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        wdog@73f98000 { /* WDOG1 */
index e3e869470cd3e4f6dc5f56daf2645f85bf6f14bc..4e735edc78ed7b4f9b6e2389091a759330e5b18c 100644 (file)
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio2: gpio@53f88000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio3: gpio@53f8c000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio4: gpio@53f90000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        wdog@53f98000 { /* WDOG1 */
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio6: gpio@53fe0000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio7: gpio@53fe4000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        i2c@53fec000 { /* I2C3 */
index db4c6096c562eaea2415570934b4cd7fad4a981a..d792581672cc0ca1710ffaa232f9837f29e722b6 100644 (file)
        };
 
        soc {
+               gpmi-nand@00112000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_gpmi_nand_1>;
+                       status = "disabled"; /* gpmi nand conflicts with SD */
+               };
+
                aips-bus@02100000 { /* AIPS2 */
                        ethernet@02188000 {
                                phy-mode = "rgmii";
index e0ec92973e7e7d253e560cb4f66fb72800be2ad9..d42e851ceb97e423fd785e3cd357ba6d70b23d8c 100644 (file)
@@ -27,6 +27,8 @@
                                ecspi@02008000 { /* eCSPI1 */
                                        fsl,spi-num-chipselects = <1>;
                                        cs-gpios = <&gpio3 19 0>;
+                                       pinctrl-names = "default";
+                                       pinctrl-0 = <&pinctrl_ecspi1_1>;
                                        status = "okay";
 
                                        flash: m25p80@0 {
                                };
                        };
 
+                       iomuxc@020e0000 {
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_gpio_hog>;
+
+                               gpios {
+                                       pinctrl_gpio_hog: gpiohog {
+                                               fsl,pins = <
+                                                          144  0x80000000      /* MX6Q_PAD_EIM_D22__GPIO_3_22 */
+                                                          121  0x80000000      /* MX6Q_PAD_EIM_D19__GPIO_3_19 */
+                                                          >;
+                                       };
+                               };
+                       };
                };
 
                aips-bus@02100000 { /* AIPS2 */
+                       usb@02184000 { /* USB OTG */
+                               vbus-supply = <&reg_usb_otg_vbus>;
+                               status = "okay";
+                       };
+
+                       usb@02184200 { /* USB1 */
+                               status = "okay";
+                       };
+
                        ethernet@02188000 {
                                phy-mode = "rgmii";
                                phy-reset-gpios = <&gpio3 23 0>;
                        regulator-max-microvolt = <3300000>;
                        regulator-always-on;
                };
+
+               reg_usb_otg_vbus: usb_otg_vbus {
+                       compatible = "regulator-fixed";
+                       regulator-name = "usb_otg_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       gpio = <&gpio3 22 0>;
+                       enable-active-high;
+               };
        };
 
        sound {
index 8c90cbac945f1d2392e590bdbb725e7154f317e5..c25d49584814aade377b4c57f964967ec1f71a09 100644 (file)
                interrupt-parent = <&intc>;
                ranges;
 
+               dma-apbh@00110000 {
+                       compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh";
+                       reg = <0x00110000 0x2000>;
+               };
+
+               gpmi-nand@00112000 {
+                      compatible = "fsl,imx6q-gpmi-nand";
+                      #address-cells = <1>;
+                      #size-cells = <1>;
+                      reg = <0x00112000 0x2000>, <0x00114000 0x2000>;
+                      reg-names = "gpmi-nand", "bch";
+                      interrupts = <0 13 0x04>, <0 15 0x04>;
+                      interrupt-names = "gpmi-dma", "bch";
+                      fsl,gpmi-dma-channel = <0>;
+                      status = "disabled";
+               };
+
                timer@00a00600 {
                        compatible = "arm,cortex-a9-twd-timer";
                        reg = <0x00a00600 0x20>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio2: gpio@020a0000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio3: gpio@020a4000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio4: gpio@020a8000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio5: gpio@020ac000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio6: gpio@020b0000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        gpio7: gpio@020b4000 {
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
-                               #interrupt-cells = <1>;
+                               #interrupt-cells = <2>;
                        };
 
                        kpp@020b8000 {
                                };
                        };
 
-                       usbphy@020c9000 { /* USBPHY1 */
+                       usbphy1: usbphy@020c9000 {
+                               compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
                                reg = <0x020c9000 0x1000>;
                                interrupts = <0 44 0x04>;
                        };
 
-                       usbphy@020ca000 { /* USBPHY2 */
+                       usbphy2: usbphy@020ca000 {
+                               compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
                                reg = <0x020ca000 0x1000>;
                                interrupts = <0 45 0x04>;
                        };
                                        };
                                };
 
+                               gpmi-nand {
+                                       pinctrl_gpmi_nand_1: gpmi-nand-1 {
+                                               fsl,pins = <1328 0xb0b1         /* MX6Q_PAD_NANDF_CLE__RAWNAND_CLE */
+                                                           1336 0xb0b1         /* MX6Q_PAD_NANDF_ALE__RAWNAND_ALE */
+                                                           1344 0xb0b1         /* MX6Q_PAD_NANDF_WP_B__RAWNAND_RESETN */
+                                                           1352 0xb000         /* MX6Q_PAD_NANDF_RB0__RAWNAND_READY0 */
+                                                           1360 0xb0b1         /* MX6Q_PAD_NANDF_CS0__RAWNAND_CE0N */
+                                                           1365 0xb0b1         /* MX6Q_PAD_NANDF_CS1__RAWNAND_CE1N */
+                                                           1371 0xb0b1         /* MX6Q_PAD_NANDF_CS2__RAWNAND_CE2N */
+                                                           1378 0xb0b1         /* MX6Q_PAD_NANDF_CS3__RAWNAND_CE3N */
+                                                           1387 0xb0b1         /* MX6Q_PAD_SD4_CMD__RAWNAND_RDN */
+                                                           1393 0xb0b1         /* MX6Q_PAD_SD4_CLK__RAWNAND_WRN */
+                                                           1397 0xb0b1         /* MX6Q_PAD_NANDF_D0__RAWNAND_D0 */
+                                                           1405 0xb0b1         /* MX6Q_PAD_NANDF_D1__RAWNAND_D1 */
+                                                           1413 0xb0b1         /* MX6Q_PAD_NANDF_D2__RAWNAND_D2 */
+                                                           1421 0xb0b1         /* MX6Q_PAD_NANDF_D3__RAWNAND_D3 */
+                                                           1429 0xb0b1         /* MX6Q_PAD_NANDF_D4__RAWNAND_D4 */
+                                                           1437 0xb0b1         /* MX6Q_PAD_NANDF_D5__RAWNAND_D5 */
+                                                           1445 0xb0b1         /* MX6Q_PAD_NANDF_D6__RAWNAND_D6 */
+                                                           1453 0xb0b1         /* MX6Q_PAD_NANDF_D7__RAWNAND_D7 */
+                                                           1463 0x00b1>;       /* MX6Q_PAD_SD4_DAT0__RAWNAND_DQS */
+                                       };
+                               };
+
                                i2c1 {
                                        pinctrl_i2c1_1: i2c1grp-1 {
                                                fsl,pins = <137 0x4001b8b1      /* MX6Q_PAD_EIM_D21__I2C1_SCL */
                                                            1517 0x17059>;      /* MX6Q_PAD_SD4_DAT7__USDHC4_DAT7 */
                                        };
                                };
+
+                               ecspi1 {
+                                       pinctrl_ecspi1_1: ecspi1grp-1 {
+                                               fsl,pins = <101 0x100b1         /* MX6Q_PAD_EIM_D17__ECSPI1_MISO */
+                                                           109 0x100b1         /* MX6Q_PAD_EIM_D18__ECSPI1_MOSI */
+                                                           94  0x100b1>;       /* MX6Q_PAD_EIM_D16__ECSPI1_SCLK */
+                                       };
+                               };
                        };
 
                        dcic@020e4000 { /* DCIC1 */
                                reg = <0x0217c000 0x4000>;
                        };
 
+                       usb@02184000 { /* USB OTG */
+                               compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
+                               reg = <0x02184000 0x200>;
+                               interrupts = <0 43 0x04>;
+                               fsl,usbphy = <&usbphy1>;
+                               status = "disabled";
+                       };
+
+                       usb@02184200 { /* USB1 */
+                               compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
+                               reg = <0x02184200 0x200>;
+                               interrupts = <0 40 0x04>;
+                               fsl,usbphy = <&usbphy2>;
+                               status = "disabled";
+                       };
+
+                       usb@02184400 { /* USB2 */
+                               compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
+                               reg = <0x02184400 0x200>;
+                               interrupts = <0 41 0x04>;
+                               status = "disabled";
+                       };
+
+                       usb@02184600 { /* USB3 */
+                               compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
+                               reg = <0x02184600 0x200>;
+                               interrupts = <0 42 0x04>;
+                               status = "disabled";
+                       };
+
                        ethernet@02188000 {
                                compatible = "fsl,imx6q-fec";
                                reg = <0x02188000 0x4000>;
index 3f5dad801a9806ad3173a0d06dedc0c4a37e8388..e5ffe960dbf3e43181d28e7519b35911c3f95f2c 100644 (file)
                slc: flash@20020000 {
                        compatible = "nxp,lpc3220-slc";
                        reg = <0x20020000 0x1000>;
-                       status = "disable";
+                       status = "disabled";
                };
 
-               mlc: flash@200B0000 {
+               mlc: flash@200a8000 {
                        compatible = "nxp,lpc3220-mlc";
-                       reg = <0x200B0000 0x1000>;
-                       status = "disable";
+                       reg = <0x200a8000 0x11000>;
+                       interrupts = <11 0>;
+                       status = "disabled";
                };
 
                dma@31000000 {
                        compatible = "nxp,ohci-nxp", "usb-ohci";
                        reg = <0x31020000 0x300>;
                        interrupts = <0x3b 0>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                usbd@31020000 {
                        compatible = "nxp,lpc3220-udc";
                        reg = <0x31020000 0x300>;
                        interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                clcd@31040000 {
                        compatible = "arm,pl110", "arm,primecell";
                        reg = <0x31040000 0x1000>;
                        interrupts = <0x0e 0>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                mac: ethernet@31060000 {
                        };
 
                        sd@20098000 {
-                               compatible = "arm,pl180", "arm,primecell";
+                               compatible = "arm,pl18x", "arm,primecell";
                                reg = <0x20098000 0x1000>;
                                interrupts = <0x0f 0>, <0x0d 0>;
+                               status = "disabled";
                        };
 
                        i2s1: i2s@2009C000 {
                                reg = <0x2009C000 0x1000>;
                        };
 
+                       /* UART5 first since it is the default console, ttyS0 */
+                       uart5: serial@40090000 {
+                               /* actually, ns16550a w/ 64 byte fifos! */
+                               compatible = "nxp,lpc3220-uart";
+                               reg = <0x40090000 0x1000>;
+                               interrupts = <9 0>;
+                               clock-frequency = <13000000>;
+                               reg-shift = <2>;
+                               status = "disabled";
+                       };
+
                        uart3: serial@40080000 {
-                               compatible = "nxp,serial";
+                               compatible = "nxp,lpc3220-uart";
                                reg = <0x40080000 0x1000>;
+                               interrupts = <7 0>;
+                               clock-frequency = <13000000>;
+                               reg-shift = <2>;
+                               status = "disabled";
                        };
 
                        uart4: serial@40088000 {
-                               compatible = "nxp,serial";
+                               compatible = "nxp,lpc3220-uart";
                                reg = <0x40088000 0x1000>;
-                       };
-
-                       uart5: serial@40090000 {
-                               compatible = "nxp,serial";
-                               reg = <0x40090000 0x1000>;
+                               interrupts = <8 0>;
+                               clock-frequency = <13000000>;
+                               reg-shift = <2>;
+                               status = "disabled";
                        };
 
                        uart6: serial@40098000 {
-                               compatible = "nxp,serial";
+                               compatible = "nxp,lpc3220-uart";
                                reg = <0x40098000 0x1000>;
+                               interrupts = <10 0>;
+                               clock-frequency = <13000000>;
+                               reg-shift = <2>;
+                               status = "disabled";
                        };
 
                        i2c1: i2c@400A0000 {
                        };
 
                        uart1: serial@40014000 {
-                               compatible = "nxp,serial";
+                               compatible = "nxp,lpc3220-hsuart";
                                reg = <0x40014000 0x1000>;
+                               interrupts = <26 0>;
+                               status = "disabled";
                        };
 
                        uart2: serial@40018000 {
-                               compatible = "nxp,serial";
+                               compatible = "nxp,lpc3220-hsuart";
                                reg = <0x40018000 0x1000>;
+                               interrupts = <25 0>;
+                               status = "disabled";
                        };
 
-                       uart7: serial@4001C000 {
-                               compatible = "nxp,serial";
-                               reg = <0x4001C000 0x1000>;
+                       uart7: serial@4001c000 {
+                               compatible = "nxp,lpc3220-hsuart";
+                               reg = <0x4001c000 0x1000>;
+                               interrupts = <24 0>;
+                               status = "disabled";
                        };
 
                        rtc@40024000 {
                                compatible = "nxp,lpc3220-adc";
                                reg = <0x40048000 0x1000>;
                                interrupts = <0x27 0>;
-                               status = "disable";
+                               status = "disabled";
                        };
 
                        tsc@40048000 {
                                compatible = "nxp,lpc3220-tsc";
                                reg = <0x40048000 0x1000>;
                                interrupts = <0x27 0>;
-                               status = "disable";
+                               status = "disabled";
                        };
 
                        key@40050000 {
                                compatible = "nxp,lpc3220-key";
                                reg = <0x40050000 0x1000>;
+                               interrupts = <54 0>;
+                               status = "disabled";
                        };
 
+                       pwm: pwm@4005C000 {
+                               compatible = "nxp,lpc3220-pwm";
+                               reg = <0x4005C000 0x8>;
+                               status = "disabled";
+                       };
                };
        };
 };
diff --git a/arch/arm/boot/dts/omap2420-h4.dts b/arch/arm/boot/dts/omap2420-h4.dts
new file mode 100644 (file)
index 0000000..25b50b7
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+/dts-v1/;
+
+/include/ "omap2.dtsi"
+
+/ {
+       model = "TI OMAP2420 H4 board";
+       compatible = "ti,omap2420-h4", "ti,omap2420", "ti,omap2";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x84000000>; /* 64 MB */
+       };
+};
index 5b4506c0a8c47d7e1ef506db75cbad9da303b3ec..cdcb98c7e0753b055c3388bd5f170950ba2964a2 100644 (file)
@@ -61,9 +61,9 @@
 };
 
 &mmc2 {
-       status = "disable";
+       status = "disabled";
 };
 
 &mmc3 {
-       status = "disable";
+       status = "disabled";
 };
index 2eee16ec59b472ad8a4c6bff23601105adabbcf8..f349ee9182ce6b12390f74718c9a978b84acd817 100644 (file)
                reg = <0x80000000 0x10000000>; /* 256 MB */
        };
 };
+
+&i2c1 {
+       clock-frequency = <2600000>;
+
+       twl: twl@48 {
+               reg = <0x48>;
+               interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+               interrupt-parent = <&intc>;
+       };
+};
+
+/include/ "twl4030.dtsi"
+
+&i2c2 {
+       clock-frequency = <400000>;
+};
+
+&i2c3 {
+       clock-frequency = <400000>;
+
+       /*
+        * TVP5146 Video decoder-in for analog input support.
+        */
+       tvp5146@5c {
+               compatible = "ti,tvp5146m2";
+               reg = <0x5c>;
+       };
+};
index 99474fa5fac4aa65585625cb77b19338fcdb84cf..810947198208c1fc8b476522b873ccb4136d4e6e 100644 (file)
                        compatible = "ti,omap3-hsmmc";
                        ti,hwmods = "mmc3";
                };
+
+               wdt2: wdt@48314000 {
+                       compatible = "ti,omap3-wdt";
+                       ti,hwmods = "wd_timer2";
+               };
        };
 };
index 1efe0c5879855ebbc4165d09f21403eb86ed9be6..9880c12877b3f5347ef4d5c84cdfadeb028a67d1 100644 (file)
                        linux,default-trigger = "mmc0";
                };
        };
+
+       sound: sound {
+               compatible = "ti,abe-twl6040";
+               ti,model = "PandaBoard";
+
+               ti,mclk-freq = <38400000>;
+
+               ti,mcpdm = <&mcpdm>;
+
+               ti,twl6040 = <&twl6040>;
+
+               /* Audio routing */
+               ti,audio-routing =
+                       "Headset Stereophone", "HSOL",
+                       "Headset Stereophone", "HSOR",
+                       "Ext Spk", "HFL",
+                       "Ext Spk", "HFR",
+                       "Line Out", "AUXL",
+                       "Line Out", "AUXR",
+                       "HSMIC", "Headset Mic",
+                       "Headset Mic", "Headset Mic Bias",
+                       "AFML", "Line In",
+                       "AFMR", "Line In";
+       };
 };
 
 &i2c1 {
                interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */
                interrupt-parent = <&gic>;
        };
+
+       twl6040: twl@4b {
+               compatible = "ti,twl6040";
+               reg = <0x4b>;
+               /* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */
+               interrupts = <0 119 4>; /* IRQ_SYS_2N cascaded to gic */
+               interrupt-parent = <&gic>;
+               ti,audpwron-gpio = <&gpio4 31 0>;  /* gpio line 127 */
+
+               vio-supply = <&v1v8>;
+               v2v1-supply = <&v2v1>;
+               enable-active-high;
+       };
 };
 
 /include/ "twl6030.dtsi"
 };
 
 &mmc2 {
-       status = "disable";
+       status = "disabled";
 };
 
 &mmc3 {
-       status = "disable";
+       status = "disabled";
 };
 
 &mmc4 {
-       status = "disable";
+       status = "disabled";
 };
 
 &mmc5 {
diff --git a/arch/arm/boot/dts/omap4-pandaES.dts b/arch/arm/boot/dts/omap4-pandaES.dts
new file mode 100644 (file)
index 0000000..d4ba43a
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+/include/ "omap4-panda.dts"
+
+/* Audio routing is differnet between PandaBoard4430 and PandaBoardES */
+&sound {
+       ti,model = "PandaBoardES";
+
+       /* Audio routing */
+       ti,audio-routing =
+               "Headset Stereophone", "HSOL",
+               "Headset Stereophone", "HSOR",
+               "Ext Spk", "HFL",
+               "Ext Spk", "HFR",
+               "Line Out", "AUXL",
+               "Line Out", "AUXR",
+               "AFML", "Line In",
+               "AFMR", "Line In";
+};
index d08c4d1372800a0f944489ace4495db188c499c7..72216e932fc0c7c8d5632a0df5173d7bfe05bbe8 100644 (file)
                regulator-boot-on;
        };
 
+       vbat: fixedregulator@2 {
+               compatible = "regulator-fixed";
+               regulator-name = "VBAT";
+               regulator-min-microvolt = <3750000>;
+               regulator-max-microvolt = <3750000>;
+               regulator-boot-on;
+       };
+
        leds {
                compatible = "gpio-leds";
                debug0 {
                        gpios = <&gpio5 11 0>; /* 139 */
                };
        };
+
+       sound {
+               compatible = "ti,abe-twl6040";
+               ti,model = "SDP4430";
+
+               ti,jack-detection = <1>;
+               ti,mclk-freq = <38400000>;
+
+               ti,mcpdm = <&mcpdm>;
+               ti,dmic = <&dmic>;
+
+               ti,twl6040 = <&twl6040>;
+
+               /* Audio routing */
+               ti,audio-routing =
+                       "Headset Stereophone", "HSOL",
+                       "Headset Stereophone", "HSOR",
+                       "Earphone Spk", "EP",
+                       "Ext Spk", "HFL",
+                       "Ext Spk", "HFR",
+                       "Line Out", "AUXL",
+                       "Line Out", "AUXR",
+                       "Vibrator", "VIBRAL",
+                       "Vibrator", "VIBRAR",
+                       "HSMIC", "Headset Mic",
+                       "Headset Mic", "Headset Mic Bias",
+                       "MAINMIC", "Main Handset Mic",
+                       "Main Handset Mic", "Main Mic Bias",
+                       "SUBMIC", "Sub Handset Mic",
+                       "Sub Handset Mic", "Main Mic Bias",
+                       "AFML", "Line In",
+                       "AFMR", "Line In",
+                       "DMic", "Digital Mic",
+                       "Digital Mic", "Digital Mic1 Bias";
+       };
 };
 
 &i2c1 {
                interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */
                interrupt-parent = <&gic>;
        };
+
+       twl6040: twl@4b {
+               compatible = "ti,twl6040";
+               reg = <0x4b>;
+               /* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */
+               interrupts = <0 119 4>; /* IRQ_SYS_2N cascaded to gic */
+               interrupt-parent = <&gic>;
+               ti,audpwron-gpio = <&gpio4 31 0>;  /* gpio line 127 */
+
+               vio-supply = <&v1v8>;
+               v2v1-supply = <&v2v1>;
+               enable-active-high;
+
+               /* regulators for vibra motor */
+               vddvibl-supply = <&vbat>;
+               vddvibr-supply = <&vbat>;
+
+               vibra {
+                       /* Vibra driver, motor resistance parameters */
+                       ti,vibldrv-res = <8>;
+                       ti,vibrdrv-res = <3>;
+                       ti,viblmotor-res = <10>;
+                       ti,vibrmotor-res = <10>;
+               };
+       };
 };
 
 /include/ "twl6030.dtsi"
 };
 
 &mmc3 {
-       status = "disable";
+       status = "disabled";
 };
 
 &mmc4 {
-       status = "disable";
+       status = "disabled";
 };
 
 &mmc5 {
diff --git a/arch/arm/boot/dts/omap4-var_som.dts b/arch/arm/boot/dts/omap4-var_som.dts
new file mode 100644 (file)
index 0000000..6601e6a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Variscite Ltd. - http://www.variscite.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.
+ */
+/dts-v1/;
+
+/include/ "omap4.dtsi"
+
+/ {
+       model = "Variscite OMAP4 SOM";
+       compatible = "var,omap4-var_som", "ti,omap4430", "ti,omap4";
+
+       memory {
+               device_type = "memory";
+               reg = <0x80000000 0x40000000>; /* 1 GB */
+       };
+
+       vdd_eth: fixedregulator@0 {
+               compatible = "regulator-fixed";
+               regulator-name = "VDD_ETH";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
+               enable-active-high;
+               regulator-boot-on;
+       };
+};
+
+&i2c1 {
+       clock-frequency = <400000>;
+
+       twl: twl@48 {
+               reg = <0x48>;
+               /* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */
+               interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */
+               interrupt-parent = <&gic>;
+       };
+};
+
+/include/ "twl6030.dtsi"
+
+&i2c2 {
+       clock-frequency = <400000>;
+};
+
+&i2c3 {
+       clock-frequency = <400000>;
+
+       /*
+        * Temperature Sensor
+        * http://www.ti.com/lit/ds/symlink/tmp105.pdf
+        */
+       tmp105@49 {
+               compatible = "ti,tmp105";
+               reg = <0x49>;
+       };
+};
+
+&i2c4 {
+       clock-frequency = <400000>;
+};
+
+&mcspi1 {
+       eth@0 {
+               compatible = "ks8851";
+               spi-max-frequency = <24000000>;
+               reg = <0>;
+               interrupt-parent = <&gpio6>;
+               interrupts = <11>; /* gpio line 171 */
+               vdd-supply = <&vdd_eth>;
+       };
+};
+
+&mmc1 {
+       vmmc-supply = <&vmmc>;
+       ti,bus-width = <8>;
+       ti,non-removable;
+};
+
+&mmc2 {
+       status = "disabled";
+};
+
+&mmc3 {
+       status = "disabled";
+};
+
+&mmc4 {
+       status = "disabled";
+};
+
+&mmc5 {
+       ti,bus-width = <4>;
+};
index 359c4979c8aab6fcc7e0ec40ed1e69ec9b3d8802..04cbbcb6ff91796ac78dfd2e15035ad32a9c89e1 100644 (file)
                        ti,hwmods = "mmc5";
                        ti,needs-special-reset;
                };
+
+               wdt2: wdt@4a314000 {
+                       compatible = "ti,omap4-wdt", "ti,omap3-wdt";
+                       ti,hwmods = "wd_timer2";
+               };
+
+               mcpdm: mcpdm@40132000 {
+                       compatible = "ti,omap4-mcpdm";
+                       reg = <0x40132000 0x7f>, /* MPU private access */
+                             <0x49032000 0x7f>; /* L3 Interconnect */
+                       interrupts = <0 112 0x4>;
+                       interrupt-parent = <&gic>;
+                       ti,hwmods = "mcpdm";
+               };
+
+               dmic: dmic@4012e000 {
+                       compatible = "ti,omap4-dmic";
+                       reg = <0x4012e000 0x7f>, /* MPU private access */
+                             <0x4902e000 0x7f>; /* L3 Interconnect */
+                       interrupts = <0 114 0x4>;
+                       interrupt-parent = <&gic>;
+                       ti,hwmods = "dmic";
+               };
        };
 };
index c4ff6d1a018bbee575fd99432c518d0ed530e769..802ec5b2fd00d0d40977624a9ae382b55e416b76 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
 
+                       nxp,wdr-clks = <14>;
+                       nxp,wwidth = <40000000>;
+                       nxp,whold = <100000000>;
+                       nxp,wsetup = <100000000>;
+                       nxp,rdr-clks = <14>;
+                       nxp,rwidth = <40000000>;
+                       nxp,rhold = <66666666>;
+                       nxp,rsetup = <100000000>;
+                       nand-on-flash-bbt;
+                       gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
                        mtd0@00000000 {
                                label = "phy3250-boot";
                                reg = <0x00000000 0x00064000>;
                };
 
                apb {
+                       uart5: serial@40090000 {
+                               status = "okay";
+                       };
+
+                       uart3: serial@40080000 {
+                               status = "okay";
+                       };
+
                        i2c1: i2c@400A0000 {
                                clock-frequency = <100000>;
 
                        };
 
                        ssp0: ssp@20084000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               pl022,num-chipselects = <1>;
+                               cs-gpios = <&gpio 3 5 0>;
+
                                eeprom: at25@0 {
+                                       pl022,hierarchy = <0>;
+                                       pl022,interface = <0>;
+                                       pl022,slave-tx-disable = <0>;
+                                       pl022,com-mode = <0>;
+                                       pl022,rx-level-trig = <1>;
+                                       pl022,tx-level-trig = <1>;
+                                       pl022,ctrl-len = <11>;
+                                       pl022,wait-state = <0>;
+                                       pl022,duplex = <0>;
+
+                                       at25,byte-len = <0x8000>;
+                                       at25,addr-mode = <2>;
+                                       at25,page-size = <64>;
+
                                        compatible = "atmel,at25";
+                                       reg = <0>;
+                                       spi-max-frequency = <5000000>;
                                };
                        };
+
+                       sd@20098000 {
+                               wp-gpios = <&gpio 3 0 0>;
+                               cd-gpios = <&gpio 3 1 0>;
+                               cd-inverted;
+                               bus-width = <4>;
+                               status = "okay";
+                       };
                };
 
                fab {
+                       uart2: serial@40018000 {
+                               status = "okay";
+                       };
+
                        tsc@40048000 {
                                status = "okay";
                        };
+
+                       key@40050000 {
+                               status = "okay";
+                               keypad,num-rows = <1>;
+                               keypad,num-columns = <1>;
+                               nxp,debounce-delay-ms = <3>;
+                               nxp,scan-delay-ms = <34>;
+                               linux,keymap = <0x00000002>;
+                       };
                };
        };
 
index ec3c339751104c43594062c30a47f2601b02b731..7e334d4cae217c8584032666b4301325944786ed 100644 (file)
@@ -77,6 +77,8 @@
                used-led {
                        label = "user_led";
                        gpios = <&gpio4 14 0x4>;
+                       default-state = "on";
+                       linux,default-trigger = "heartbeat";
                };
        };
 
                        };
                };
 
+               // External Micro SD slot
                sdi@80126000 {
-                       status = "enabled";
+                       arm,primecell-periphid = <0x10480180>;
+                       max-frequency = <50000000>;
+                       bus-width = <8>;
+                       mmc-cap-mmc-highspeed;
                        vmmc-supply = <&ab8500_ldo_aux3_reg>;
+
+                       #gpio-cells = <1>;
                        cd-gpios  = <&gpio6 26 0x4>; // 218
+                       cd-inverted;
+
+                       status = "okay";
                };
 
+               // On-board eMMC
                sdi@80114000 {
-                       status = "enabled";
+                       arm,primecell-periphid = <0x10480180>;
+                       max-frequency = <50000000>;
+                       bus-width = <8>;
+                       mmc-cap-mmc-highspeed;
                        vmmc-supply = <&ab8500_ldo_aux2_reg>;
+
+                       status = "okay";
                };
 
                uart@80120000 {
index 10dcec7e7321be6b3a68e05d021a47cbf5e35601..f7b84aced654ca643bc49ebe83b376425a6b893f 100644 (file)
@@ -43,8 +43,8 @@
 
        pmu {
                compatible = "arm,cortex-a9-pmu";
-               interrupts = <0 8 0x04
-                             0 9 0x04>;
+               interrupts = <0 6 0x04
+                             0 7 0x04>;
        };
 
        L2: l2-cache {
                gmac0: eth@e2000000 {
                        compatible = "st,spear600-gmac";
                        reg = <0xe2000000 0x8000>;
-                       interrupts = <0 23 0x4
-                                     0 24 0x4>;
+                       interrupts = <0 33 0x4
+                                     0 34 0x4>;
                        interrupt-names = "macirq", "eth_wake_irq";
                        status = "disabled";
                };
                        kbd@e0300000 {
                                compatible = "st,spear300-kbd";
                                reg = <0xe0300000 0x1000>;
+                               interrupts = <0 52 0x4>;
                                status = "disabled";
                        };
 
                        serial@e0000000 {
                                compatible = "arm,pl011", "arm,primecell";
                                reg = <0xe0000000 0x1000>;
-                               interrupts = <0 36 0x4>;
+                               interrupts = <0 35 0x4>;
                                status = "disabled";
                        };
 
index c13fd1f3b09f7320b189e6a0795bfd4711969825..e4e912f9502466da3ab44a26eda9f8c83e383d8e 100644 (file)
@@ -15,8 +15,8 @@
 /include/ "spear320.dtsi"
 
 / {
-       model = "ST SPEAr300 Evaluation Board";
-       compatible = "st,spear300-evb", "st,spear300";
+       model = "ST SPEAr320 Evaluation Board";
+       compatible = "st,spear320-evb", "st,spear320";
        #address-cells = <1>;
        #size-cells = <1>;
 
@@ -26,7 +26,7 @@
 
        ahb {
                pinmux@b3000000 {
-                       st,pinmux-mode = <3>;
+                       st,pinmux-mode = <4>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&state_default>;
 
index 089f0a42c50ef4244765efc59450011637e33a08..a3c36e47d7efcafee29eb73865eb5dec5651d4a4 100644 (file)
                        timer@f0000000 {
                                compatible = "st,spear-timer";
                                reg = <0xf0000000 0x400>;
+                               interrupt-parent = <&vic0>;
                                interrupts = <16>;
                        };
                };
similarity index 99%
rename from arch/arm/boot/dts/tegra-harmony.dts
rename to arch/arm/boot/dts/tegra20-harmony.dts
index 7de701365fce6b9e6594e16491ad97da9cfa75fb..f146dbf6f7f8c40f0a453d0e2d09887943ceef3f 100644 (file)
                cd-gpios = <&gpio 58 0>; /* gpio PH2 */
                wp-gpios = <&gpio 59 0>; /* gpio PH3 */
                power-gpios = <&gpio 70 0>; /* gpio PI6 */
-               support-8bit;
                bus-width = <8>;
        };
 
similarity index 99%
rename from arch/arm/boot/dts/tegra-paz00.dts
rename to arch/arm/boot/dts/tegra20-paz00.dts
index bfeb117d5aea639bdd0f8949796593b4d881da26..684a9e1ff7e9c05d1479c071e3d4658c652337ee 100644 (file)
 
        sdhci@c8000600 {
                status = "okay";
-               support-8bit;
                bus-width = <8>;
        };
 
similarity index 88%
rename from arch/arm/boot/dts/tegra-seaboard.dts
rename to arch/arm/boot/dts/tegra20-seaboard.dts
index 89cb7f2acd92cfa9ebbe8ceb8bb18823d62ceeeb..85e621ab2968d2947bf0b6dac96a305d5afbf614 100644 (file)
                                nvidia,pins = "dap4";
                                nvidia,function = "dap4";
                        };
-                       ddc {
-                               nvidia,pins = "ddc", "owc", "spdi", "spdo",
-                                       "uac";
-                               nvidia,function = "rsvd2";
-                       };
                        dta {
                                nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
                                nvidia,function = "vi";
                                        "lspi", "lvp1", "lvs";
                                nvidia,function = "displaya";
                        };
+                       owc {
+                               nvidia,pins = "owc", "spdi", "spdo", "uac";
+                               nvidia,function = "rsvd2";
+                       };
                        pmc {
                                nvidia,pins = "pmc";
                                nvidia,function = "pwr_on";
                        };
-                       pta {
-                               nvidia,pins = "pta";
-                               nvidia,function = "i2c2";
-                       };
                        rm {
                                nvidia,pins = "rm";
                                nvidia,function = "i2c1";
                        conf_ata {
                                nvidia,pins = "ata", "atb", "atc", "atd",
                                        "cdev1", "cdev2", "dap1", "dap2",
-                                       "dap4", "dtf", "gma", "gmc", "gmd",
+                                       "dap4", "ddc", "dtf", "gma", "gmc", "gmd",
                                        "gme", "gpu", "gpu7", "i2cp", "irrx",
                                        "irtx", "pta", "rm", "sdc", "sdd",
                                        "slxd", "slxk", "spdi", "spdo", "uac",
                                nvidia,tristate = <0>;
                        };
                        conf_ate {
-                               nvidia,pins = "ate", "csus", "dap3", "ddc",
+                               nvidia,pins = "ate", "csus", "dap3",
                                        "gpv", "owc", "slxc", "spib", "spid",
                                        "spie";
                                nvidia,pull = <0>;
                                nvidia,slew-rate-falling = <3>;
                        };
                };
+
+               state_i2cmux_ddc: pinmux_i2cmux_ddc {
+                       ddc {
+                               nvidia,pins = "ddc";
+                               nvidia,function = "i2c2";
+                       };
+                       pta {
+                               nvidia,pins = "pta";
+                               nvidia,function = "rsvd4";
+                       };
+               };
+
+               state_i2cmux_pta: pinmux_i2cmux_pta {
+                       ddc {
+                               nvidia,pins = "ddc";
+                               nvidia,function = "rsvd4";
+                       };
+                       pta {
+                               nvidia,pins = "pta";
+                               nvidia,function = "i2c2";
+                       };
+               };
+
+               state_i2cmux_idle: pinmux_i2cmux_idle {
+                       ddc {
+                               nvidia,pins = "ddc";
+                               nvidia,function = "rsvd4";
+                       };
+                       pta {
+                               nvidia,pins = "pta";
+                               nvidia,function = "rsvd4";
+                       };
+               };
        };
 
        i2s@70002800 {
        i2c@7000c400 {
                status = "okay";
                clock-frequency = <100000>;
+       };
+
+       i2cmux {
+               compatible = "i2c-mux-pinctrl";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               i2c-parent = <&{/i2c@7000c400}>;
 
-               smart-battery@b {
-                       compatible = "ti,bq20z75", "smart-battery-1.1";
-                       reg = <0xb>;
-                       ti,i2c-retry-count = <2>;
-                       ti,poll-retry-count = <10>;
+               pinctrl-names = "ddc", "pta", "idle";
+               pinctrl-0 = <&state_i2cmux_ddc>;
+               pinctrl-1 = <&state_i2cmux_pta>;
+               pinctrl-2 = <&state_i2cmux_idle>;
+
+               i2c@0 {
+                       reg = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               i2c@1 {
+                       reg = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       smart-battery@b {
+                               compatible = "ti,bq20z75", "smart-battery-1.1";
+                               reg = <0xb>;
+                               ti,i2c-retry-count = <2>;
+                               ti,poll-retry-count = <10>;
+                       };
                };
        };
 
                };
        };
 
-       emc {
+       memory-controller@0x7000f400 {
                emc-table@190000 {
                        reg = <190000>;
                        compatible = "nvidia,tegra20-emc-table";
 
        sdhci@c8000600 {
                status = "okay";
-               support-8bit;
                bus-width = <8>;
        };
 
similarity index 99%
rename from arch/arm/boot/dts/tegra-ventana.dts
rename to arch/arm/boot/dts/tegra20-ventana.dts
index 445343b0fbdd7bc7eedbd989196bac17f7ffc383..be90544e6b590ca44b81aa0b119eb1dca504238c 100644 (file)
 
        sdhci@c8000600 {
                status = "okay";
-               support-8bit;
                bus-width = <8>;
        };
 
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
new file mode 100644 (file)
index 0000000..6916310
--- /dev/null
@@ -0,0 +1,301 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+       model = "NVIDIA Tegra2 Whistler evaluation board";
+       compatible = "nvidia,whistler", "nvidia,tegra20";
+
+       memory {
+               reg = <0x00000000 0x20000000>;
+       };
+
+       pinmux {
+               pinctrl-names = "default";
+               pinctrl-0 = <&state_default>;
+
+               state_default: pinmux {
+                       ata {
+                               nvidia,pins = "ata", "atb", "ate", "gma", "gmb",
+                                       "gmc", "gmd", "gpu";
+                               nvidia,function = "gmi";
+                       };
+                       atc {
+                               nvidia,pins = "atc", "atd";
+                               nvidia,function = "sdio4";
+                       };
+                       cdev1 {
+                               nvidia,pins = "cdev1";
+                               nvidia,function = "plla_out";
+                       };
+                       cdev2 {
+                               nvidia,pins = "cdev2";
+                               nvidia,function = "osc";
+                       };
+                       crtp {
+                               nvidia,pins = "crtp";
+                               nvidia,function = "crt";
+                       };
+                       csus {
+                               nvidia,pins = "csus";
+                               nvidia,function = "vi_sensor_clk";
+                       };
+                       dap1 {
+                               nvidia,pins = "dap1";
+                               nvidia,function = "dap1";
+                       };
+                       dap2 {
+                               nvidia,pins = "dap2";
+                               nvidia,function = "dap2";
+                       };
+                       dap3 {
+                               nvidia,pins = "dap3";
+                               nvidia,function = "dap3";
+                       };
+                       dap4 {
+                               nvidia,pins = "dap4";
+                               nvidia,function = "dap4";
+                       };
+                       ddc {
+                               nvidia,pins = "ddc";
+                               nvidia,function = "i2c2";
+                       };
+                       dta {
+                               nvidia,pins = "dta", "dtb", "dtc", "dtd";
+                               nvidia,function = "vi";
+                       };
+                       dte {
+                               nvidia,pins = "dte";
+                               nvidia,function = "rsvd1";
+                       };
+                       dtf {
+                               nvidia,pins = "dtf";
+                               nvidia,function = "i2c3";
+                       };
+                       gme {
+                               nvidia,pins = "gme";
+                               nvidia,function = "dap5";
+                       };
+                       gpu7 {
+                               nvidia,pins = "gpu7";
+                               nvidia,function = "rtck";
+                       };
+                       gpv {
+                               nvidia,pins = "gpv";
+                               nvidia,function = "pcie";
+                       };
+                       hdint {
+                               nvidia,pins = "hdint", "pta";
+                               nvidia,function = "hdmi";
+                       };
+                       i2cp {
+                               nvidia,pins = "i2cp";
+                               nvidia,function = "i2cp";
+                       };
+                       irrx {
+                               nvidia,pins = "irrx", "irtx";
+                               nvidia,function = "uartb";
+                       };
+                       kbca {
+                               nvidia,pins = "kbca", "kbcc", "kbce", "kbcf";
+                               nvidia,function = "kbc";
+                       };
+                       kbcb {
+                               nvidia,pins = "kbcb", "kbcd";
+                               nvidia,function = "sdio2";
+                       };
+                       lcsn {
+                               nvidia,pins = "lcsn", "lsck", "lsda", "lsdi",
+                                       "spia", "spib", "spic";
+                               nvidia,function = "spi3";
+                       };
+                       ld0 {
+                               nvidia,pins = "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",
+                                       "lm1", "lpp", "lpw0", "lpw1", "lpw2",
+                                       "lsc0", "lsc1", "lspi", "lvp0", "lvp1",
+                                       "lvs";
+                               nvidia,function = "displaya";
+                       };
+                       owc {
+                               nvidia,pins = "owc", "uac";
+                               nvidia,function = "owr";
+                       };
+                       pmc {
+                               nvidia,pins = "pmc";
+                               nvidia,function = "pwr_on";
+                       };
+                       rm {
+                               nvidia,pins = "rm";
+                               nvidia,function = "i2c1";
+                       };
+                       sdb {
+                               nvidia,pins = "sdb", "sdc", "sdd", "slxa",
+                                       "slxc", "slxd", "slxk";
+                               nvidia,function = "sdio3";
+                       };
+                       sdio1 {
+                               nvidia,pins = "sdio1";
+                               nvidia,function = "sdio1";
+                       };
+                       spdi {
+                               nvidia,pins = "spdi", "spdo";
+                               nvidia,function = "rsvd2";
+                       };
+                       spid {
+                               nvidia,pins = "spid", "spie", "spig", "spih";
+                               nvidia,function = "spi2_alt";
+                       };
+                       spif {
+                               nvidia,pins = "spif";
+                               nvidia,function = "spi2";
+                       };
+                       uaa {
+                               nvidia,pins = "uaa", "uab";
+                               nvidia,function = "uarta";
+                       };
+                       uad {
+                               nvidia,pins = "uad";
+                               nvidia,function = "irda";
+                       };
+                       uca {
+                               nvidia,pins = "uca", "ucb";
+                               nvidia,function = "uartc";
+                       };
+                       uda {
+                               nvidia,pins = "uda";
+                               nvidia,function = "spi1";
+                       };
+                       conf_ata {
+                               nvidia,pins = "ata", "atb", "atc", "ddc", "gma",
+                                       "gmb", "gmc", "gmd", "irrx", "irtx",
+                                       "kbca", "kbcb", "kbcc", "kbcd", "kbce",
+                                       "kbcf", "sdc", "sdd", "spie", "spig",
+                                       "spih", "uaa", "uab", "uad", "uca",
+                                       "ucb";
+                               nvidia,pull = <2>;
+                               nvidia,tristate = <0>;
+                       };
+                       conf_atd {
+                               nvidia,pins = "atd", "ate", "cdev1", "csus",
+                                       "dap1", "dap2", "dap3", "dap4", "dte",
+                                       "dtf", "gpu", "gpu7", "gpv", "i2cp",
+                                       "rm", "sdio1", "slxa", "slxc", "slxd",
+                                       "slxk", "spdi", "spdo", "uac", "uda";
+                               nvidia,pull = <0>;
+                               nvidia,tristate = <0>;
+                       };
+                       conf_cdev2 {
+                               nvidia,pins = "cdev2", "spia", "spib";
+                               nvidia,pull = <1>;
+                               nvidia,tristate = <1>;
+                       };
+                       conf_ck32 {
+                               nvidia,pins = "ck32", "ddrc", "lc", "pmca",
+                                       "pmcb", "pmcc", "pmcd", "xm2c",
+                                       "xm2d";
+                               nvidia,pull = <0>;
+                       };
+                       conf_crtp {
+                               nvidia,pins = "crtp";
+                               nvidia,pull = <0>;
+                               nvidia,tristate = <1>;
+                       };
+                       conf_dta {
+                               nvidia,pins = "dta", "dtb", "dtc", "dtd",
+                                       "spid", "spif";
+                               nvidia,pull = <1>;
+                               nvidia,tristate = <0>;
+                       };
+                       conf_gme {
+                               nvidia,pins = "gme", "owc", "pta", "spic";
+                               nvidia,pull = <2>;
+                               nvidia,tristate = <1>;
+                       };
+                       conf_ld17_0 {
+                               nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+                                       "ld23_22";
+                               nvidia,pull = <1>;
+                       };
+                       conf_ls {
+                               nvidia,pins = "ls", "pmce";
+                               nvidia,pull = <2>;
+                       };
+                       drive_dap1 {
+                               nvidia,pins = "drive_dap1";
+                               nvidia,high-speed-mode = <0>;
+                               nvidia,schmitt = <1>;
+                               nvidia,low-power-mode = <0>;
+                               nvidia,pull-down-strength = <0>;
+                               nvidia,pull-up-strength = <0>;
+                               nvidia,slew-rate-rising = <0>;
+                               nvidia,slew-rate-falling = <0>;
+                       };
+               };
+       };
+
+       i2s@70002800 {
+               status = "okay";
+       };
+
+       serial@70006000 {
+               status = "okay";
+               clock-frequency = <216000000>;
+       };
+
+       i2c@7000d000 {
+               status = "okay";
+               clock-frequency = <100000>;
+
+               codec: codec@1a {
+                       compatible = "wlf,wm8753";
+                       reg = <0x1a>;
+               };
+
+               tca6416: gpio@20 {
+                       compatible = "ti,tca6416";
+                       reg = <0x20>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
+       };
+
+       usb@c5000000 {
+               status = "okay";
+               nvidia,vbus-gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
+       };
+
+       usb@c5008000 {
+               status = "okay";
+               nvidia,vbus-gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
+       };
+
+       sdhci@c8000400 {
+               status = "okay";
+               wp-gpios = <&gpio 173 0>; /* gpio PV5 */
+               bus-width = <8>;
+       };
+
+       sdhci@c8000600 {
+               status = "okay";
+               bus-width = <8>;
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-wm8753-whistler",
+                            "nvidia,tegra-audio-wm8753";
+               nvidia,model = "NVIDIA Tegra Whistler";
+
+               nvidia,audio-routing =
+                       "Headphone Jack", "LOUT1",
+                       "Headphone Jack", "ROUT1",
+                       "MIC2", "Mic Jack",
+                       "MIC2N", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&codec>;
+       };
+};
index c417d67e902755df968f812a9fe4f94101cbb796..9f1921634eb7b8ab19c671fc2de17f0d44a50fc4 100644 (file)
@@ -72,7 +72,7 @@
                reg = <0x70002800 0x200>;
                interrupts = <0 13 0x04>;
                nvidia,dma-request-selector = <&apbdma 2>;
-               status = "disable";
+               status = "disabled";
        };
 
        tegra_i2s2: i2s@70002a00 {
@@ -80,7 +80,7 @@
                reg = <0x70002a00 0x200>;
                interrupts = <0 3 0x04>;
                nvidia,dma-request-selector = <&apbdma 1>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006000 {
@@ -88,7 +88,7 @@
                reg = <0x70006000 0x40>;
                reg-shift = <2>;
                interrupts = <0 36 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006040 {
@@ -96,7 +96,7 @@
                reg = <0x70006040 0x40>;
                reg-shift = <2>;
                interrupts = <0 37 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006200 {
                reg = <0x70006200 0x100>;
                reg-shift = <2>;
                interrupts = <0 46 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006300 {
                reg = <0x70006300 0x100>;
                reg-shift = <2>;
                interrupts = <0 90 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006400 {
                reg = <0x70006400 0x100>;
                reg-shift = <2>;
                interrupts = <0 91 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000c000 {
                interrupts = <0 38 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000c400 {
                interrupts = <0 84 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000c500 {
                interrupts = <0 92 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000d000 {
                interrupts = <0 53 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        pmc {
                reg = <0x7000e400 0x400>;
        };
 
-       mc {
+       memory-controller@0x7000f000 {
                compatible = "nvidia,tegra20-mc";
                reg = <0x7000f000 0x024
                       0x7000f03c 0x3c4>;
                       0x58000000 0x02000000>;  /* GART aperture */
        };
 
-       emc {
+       memory-controller@0x7000f400 {
                compatible = "nvidia,tegra20-emc";
                reg = <0x7000f400 0x200>;
                #address-cells = <1>;
                interrupts = <0 20 0x04>;
                phy_type = "utmi";
                nvidia,has-legacy-mode;
-               status = "disable";
+               status = "disabled";
        };
 
        usb@c5004000 {
                reg = <0xc5004000 0x4000>;
                interrupts = <0 21 0x04>;
                phy_type = "ulpi";
-               status = "disable";
+               status = "disabled";
        };
 
        usb@c5008000 {
                reg = <0xc5008000 0x4000>;
                interrupts = <0 97 0x04>;
                phy_type = "utmi";
-               status = "disable";
+               status = "disabled";
        };
 
        sdhci@c8000000 {
                compatible = "nvidia,tegra20-sdhci";
                reg = <0xc8000000 0x200>;
                interrupts = <0 14 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        sdhci@c8000200 {
                compatible = "nvidia,tegra20-sdhci";
                reg = <0xc8000200 0x200>;
                interrupts = <0 15 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        sdhci@c8000400 {
                compatible = "nvidia,tegra20-sdhci";
                reg = <0xc8000400 0x200>;
                interrupts = <0 19 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        sdhci@c8000600 {
                compatible = "nvidia,tegra20-sdhci";
                reg = <0xc8000600 0x200>;
                interrupts = <0 31 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        pmu {
similarity index 99%
rename from arch/arm/boot/dts/tegra-cardhu.dts
rename to arch/arm/boot/dts/tegra30-cardhu.dts
index 36321bceec46beb8ae812bc1ff5e80f2db45fab0..c169bced131e32038f4523f599c054b22690bdb6 100644 (file)
 
        sdhci@78000600 {
                status = "okay";
-               support-8bit;
                bus-width = <8>;
        };
 
index 2dcc09e784b58713cb514fe89044cd821c6a82e3..da740191771f8493f1734636a88244869be5abff 100644 (file)
@@ -82,7 +82,7 @@
                reg = <0x70006000 0x40>;
                reg-shift = <2>;
                interrupts = <0 36 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006040 {
@@ -90,7 +90,7 @@
                reg = <0x70006040 0x40>;
                reg-shift = <2>;
                interrupts = <0 37 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006200 {
@@ -98,7 +98,7 @@
                reg = <0x70006200 0x100>;
                reg-shift = <2>;
                interrupts = <0 46 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006300 {
                reg = <0x70006300 0x100>;
                reg-shift = <2>;
                interrupts = <0 90 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        serial@70006400 {
                reg = <0x70006400 0x100>;
                reg-shift = <2>;
                interrupts = <0 91 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000c000 {
                interrupts = <0 38 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000c400 {
                interrupts = <0 84 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000c500 {
                interrupts = <0 92 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000c700 {
                interrupts = <0 120 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        i2c@7000d000 {
                interrupts = <0 53 0x04>;
                #address-cells = <1>;
                #size-cells = <0>;
-               status = "disable";
+               status = "disabled";
        };
 
        pmc {
                reg = <0x7000e400 0x400>;
        };
 
-       mc {
+       memory-controller {
                compatible = "nvidia,tegra30-mc";
                reg = <0x7000f000 0x010
                       0x7000f03c 0x1b4
                        compatible = "nvidia,tegra30-i2s";
                        reg = <0x70080300 0x100>;
                        nvidia,ahub-cif-ids = <4 4>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                tegra_i2s1: i2s@70080400 {
                        compatible = "nvidia,tegra30-i2s";
                        reg = <0x70080400 0x100>;
                        nvidia,ahub-cif-ids = <5 5>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                tegra_i2s2: i2s@70080500 {
                        compatible = "nvidia,tegra30-i2s";
                        reg = <0x70080500 0x100>;
                        nvidia,ahub-cif-ids = <6 6>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                tegra_i2s3: i2s@70080600 {
                        compatible = "nvidia,tegra30-i2s";
                        reg = <0x70080600 0x100>;
                        nvidia,ahub-cif-ids = <7 7>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                tegra_i2s4: i2s@70080700 {
                        compatible = "nvidia,tegra30-i2s";
                        reg = <0x70080700 0x100>;
                        nvidia,ahub-cif-ids = <8 8>;
-                       status = "disable";
+                       status = "disabled";
                };
        };
 
                compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
                reg = <0x78000000 0x200>;
                interrupts = <0 14 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        sdhci@78000200 {
                compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
                reg = <0x78000200 0x200>;
                interrupts = <0 15 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        sdhci@78000400 {
                compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
                reg = <0x78000400 0x200>;
                interrupts = <0 19 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        sdhci@78000600 {
                compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci";
                reg = <0x78000600 0x200>;
                interrupts = <0 31 0x04>;
-               status = "disable";
+               status = "disabled";
        };
 
        pmu {
index 16076e2d093410b25dd3f8e1f43e38ef57f8ffd7..d8a827bd2bf3728984621d1c45d90b640e8373db 100644 (file)
@@ -55,6 +55,8 @@
                        reg-io-width = <4>;
                        smsc,irq-active-high;
                        smsc,irq-push-pull;
+                       vdd33a-supply = <&v2m_fixed_3v3>;
+                       vddvario-supply = <&v2m_fixed_3v3>;
                };
 
                usb@2,03000000 {
                        v2m_timer23: timer@120000 {
                                compatible = "arm,sp804", "arm,primecell";
                                reg = <0x120000 0x1000>;
+                               interrupts = <3>;
                        };
 
                        /* DVI I2C bus */
                                interrupts = <14>;
                        };
                };
+
+               v2m_fixed_3v3: fixedregulator@0 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3V3";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
        };
 };
index a6c9c7c82d5357aee7640b6176dc71789003e364..dba53fd026bb3692ecf33d69d237a2f9356c4bd1 100644 (file)
@@ -54,6 +54,8 @@
                        reg-io-width = <4>;
                        smsc,irq-active-high;
                        smsc,irq-push-pull;
+                       vdd33a-supply = <&v2m_fixed_3v3>;
+                       vddvario-supply = <&v2m_fixed_3v3>;
                };
 
                usb@3,03000000 {
                        v2m_timer23: timer@12000 {
                                compatible = "arm,sp804", "arm,primecell";
                                reg = <0x12000 0x1000>;
+                               interrupts = <3>;
                        };
 
                        /* DVI I2C bus */
                                interrupts = <14>;
                        };
                };
+
+               v2m_fixed_3v3: fixedregulator@0 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3V3";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
        };
 };
index 7e1091d91af8b9d999b795414ebf0110c42b65c0..d12b34ca05685fd04b0c500088c74740bcacfc84 100644 (file)
@@ -14,8 +14,8 @@
        arm,hbi = <0x237>;
        compatible = "arm,vexpress,v2p-ca15,tc1", "arm,vexpress,v2p-ca15", "arm,vexpress";
        interrupt-parent = <&gic>;
-       #address-cells = <1>;
-       #size-cells = <1>;
+       #address-cells = <2>;
+       #size-cells = <2>;
 
        chosen { };
 
 
        memory@80000000 {
                device_type = "memory";
-               reg = <0x80000000 0x40000000>;
+               reg = <0 0x80000000 0 0x40000000>;
        };
 
        hdlcd@2b000000 {
                compatible = "arm,hdlcd";
-               reg = <0x2b000000 0x1000>;
+               reg = <0 0x2b000000 0 0x1000>;
                interrupts = <0 85 4>;
        };
 
        memory-controller@2b0a0000 {
                compatible = "arm,pl341", "arm,primecell";
-               reg = <0x2b0a0000 0x1000>;
+               reg = <0 0x2b0a0000 0 0x1000>;
        };
 
        wdt@2b060000 {
                compatible = "arm,sp805", "arm,primecell";
-               reg = <0x2b060000 0x1000>;
+               reg = <0 0x2b060000 0 0x1000>;
                interrupts = <98>;
        };
 
                #interrupt-cells = <3>;
                #address-cells = <0>;
                interrupt-controller;
-               reg = <0x2c001000 0x1000>,
-                     <0x2c002000 0x1000>,
-                     <0x2c004000 0x2000>,
-                     <0x2c006000 0x2000>;
+               reg = <0 0x2c001000 0 0x1000>,
+                     <0 0x2c002000 0 0x1000>,
+                     <0 0x2c004000 0 0x2000>,
+                     <0 0x2c006000 0 0x2000>;
                interrupts = <1 9 0xf04>;
        };
 
        memory-controller@7ffd0000 {
                compatible = "arm,pl354", "arm,primecell";
-               reg = <0x7ffd0000 0x1000>;
+               reg = <0 0x7ffd0000 0 0x1000>;
                interrupts = <0 86 4>,
                             <0 87 4>;
        };
 
        dma@7ffb0000 {
                compatible = "arm,pl330", "arm,primecell";
-               reg = <0x7ffb0000 0x1000>;
+               reg = <0 0x7ffb0000 0 0x1000>;
                interrupts = <0 92 4>,
                             <0 88 4>,
                             <0 89 4>,
        };
 
        motherboard {
-               ranges = <0 0 0x08000000 0x04000000>,
-                        <1 0 0x14000000 0x04000000>,
-                        <2 0 0x18000000 0x04000000>,
-                        <3 0 0x1c000000 0x04000000>,
-                        <4 0 0x0c000000 0x04000000>,
-                        <5 0 0x10000000 0x04000000>;
+               ranges = <0 0 0 0x08000000 0x04000000>,
+                        <1 0 0 0x14000000 0x04000000>,
+                        <2 0 0 0x18000000 0x04000000>,
+                        <3 0 0 0x1c000000 0x04000000>,
+                        <4 0 0 0x0c000000 0x04000000>,
+                        <5 0 0 0x10000000 0x04000000>;
 
                interrupt-map-mask = <0 0 63>;
                interrupt-map = <0 0  0 &gic 0  0 4>,
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
new file mode 100644 (file)
index 0000000..4890a81
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ * CoreTile Express A15x2 A7x3
+ * Cortex-A15_A7 MPCore (V2P-CA15_A7)
+ *
+ * HBI-0249A
+ */
+
+/dts-v1/;
+
+/ {
+       model = "V2P-CA15_CA7";
+       arm,hbi = <0x249>;
+       compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress";
+       interrupt-parent = <&gic>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       chosen { };
+
+       aliases {
+               serial0 = &v2m_serial0;
+               serial1 = &v2m_serial1;
+               serial2 = &v2m_serial2;
+               serial3 = &v2m_serial3;
+               i2c0 = &v2m_i2c_dvi;
+               i2c1 = &v2m_i2c_pcie;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: cpu@0 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a15";
+                       reg = <0>;
+               };
+
+               cpu1: cpu@1 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a15";
+                       reg = <1>;
+               };
+
+/* A7s disabled till big.LITTLE patches are available...
+               cpu2: cpu@2 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x100>;
+               };
+
+               cpu3: cpu@3 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x101>;
+               };
+
+               cpu4: cpu@4 {
+                       device_type = "cpu";
+                       compatible = "arm,cortex-a7";
+                       reg = <0x102>;
+               };
+*/
+       };
+
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0 0x80000000 0 0x40000000>;
+       };
+
+       wdt@2a490000 {
+               compatible = "arm,sp805", "arm,primecell";
+               reg = <0 0x2a490000 0 0x1000>;
+               interrupts = <98>;
+       };
+
+       hdlcd@2b000000 {
+               compatible = "arm,hdlcd";
+               reg = <0 0x2b000000 0 0x1000>;
+               interrupts = <0 85 4>;
+       };
+
+       memory-controller@2b0a0000 {
+               compatible = "arm,pl341", "arm,primecell";
+               reg = <0 0x2b0a0000 0 0x1000>;
+       };
+
+       gic: interrupt-controller@2c001000 {
+               compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+               #interrupt-cells = <3>;
+               #address-cells = <0>;
+               interrupt-controller;
+               reg = <0 0x2c001000 0 0x1000>,
+                     <0 0x2c002000 0 0x1000>,
+                     <0 0x2c004000 0 0x2000>,
+                     <0 0x2c006000 0 0x2000>;
+               interrupts = <1 9 0xf04>;
+       };
+
+       memory-controller@7ffd0000 {
+               compatible = "arm,pl354", "arm,primecell";
+               reg = <0 0x7ffd0000 0 0x1000>;
+               interrupts = <0 86 4>,
+                            <0 87 4>;
+       };
+
+       dma@7ff00000 {
+               compatible = "arm,pl330", "arm,primecell";
+               reg = <0 0x7ff00000 0 0x1000>;
+               interrupts = <0 92 4>,
+                            <0 88 4>,
+                            <0 89 4>,
+                            <0 90 4>,
+                            <0 91 4>;
+       };
+
+       timer {
+               compatible = "arm,armv7-timer";
+               interrupts = <1 13 0xf08>,
+                            <1 14 0xf08>,
+                            <1 11 0xf08>,
+                            <1 10 0xf08>;
+       };
+
+       pmu {
+               compatible = "arm,cortex-a15-pmu", "arm,cortex-a9-pmu";
+               interrupts = <0 68 4>,
+                            <0 69 4>;
+       };
+
+       motherboard {
+               ranges = <0 0 0 0x08000000 0x04000000>,
+                        <1 0 0 0x14000000 0x04000000>,
+                        <2 0 0 0x18000000 0x04000000>,
+                        <3 0 0 0x1c000000 0x04000000>,
+                        <4 0 0 0x0c000000 0x04000000>,
+                        <5 0 0 0x10000000 0x04000000>;
+
+               interrupt-map-mask = <0 0 63>;
+               interrupt-map = <0 0  0 &gic 0  0 4>,
+                               <0 0  1 &gic 0  1 4>,
+                               <0 0  2 &gic 0  2 4>,
+                               <0 0  3 &gic 0  3 4>,
+                               <0 0  4 &gic 0  4 4>,
+                               <0 0  5 &gic 0  5 4>,
+                               <0 0  6 &gic 0  6 4>,
+                               <0 0  7 &gic 0  7 4>,
+                               <0 0  8 &gic 0  8 4>,
+                               <0 0  9 &gic 0  9 4>,
+                               <0 0 10 &gic 0 10 4>,
+                               <0 0 11 &gic 0 11 4>,
+                               <0 0 12 &gic 0 12 4>,
+                               <0 0 13 &gic 0 13 4>,
+                               <0 0 14 &gic 0 14 4>,
+                               <0 0 15 &gic 0 15 4>,
+                               <0 0 16 &gic 0 16 4>,
+                               <0 0 17 &gic 0 17 4>,
+                               <0 0 18 &gic 0 18 4>,
+                               <0 0 19 &gic 0 19 4>,
+                               <0 0 20 &gic 0 20 4>,
+                               <0 0 21 &gic 0 21 4>,
+                               <0 0 22 &gic 0 22 4>,
+                               <0 0 23 &gic 0 23 4>,
+                               <0 0 24 &gic 0 24 4>,
+                               <0 0 25 &gic 0 25 4>,
+                               <0 0 26 &gic 0 26 4>,
+                               <0 0 27 &gic 0 27 4>,
+                               <0 0 28 &gic 0 28 4>,
+                               <0 0 29 &gic 0 29 4>,
+                               <0 0 30 &gic 0 30 4>,
+                               <0 0 31 &gic 0 31 4>,
+                               <0 0 32 &gic 0 32 4>,
+                               <0 0 33 &gic 0 33 4>,
+                               <0 0 34 &gic 0 34 4>,
+                               <0 0 35 &gic 0 35 4>,
+                               <0 0 36 &gic 0 36 4>,
+                               <0 0 37 &gic 0 37 4>,
+                               <0 0 38 &gic 0 38 4>,
+                               <0 0 39 &gic 0 39 4>,
+                               <0 0 40 &gic 0 40 4>,
+                               <0 0 41 &gic 0 41 4>,
+                               <0 0 42 &gic 0 42 4>;
+       };
+};
+
+/include/ "vexpress-v2m-rs1.dtsi"
index 4fa60547494ad7f160d5b512de2edbe17cd43a77..eceed186a3c1c0376105c94096b466f7ca3db794 100644 (file)
@@ -1,5 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
@@ -16,8 +18,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ARCH_LPC32XX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_ZBOOT_ROM_TEXT=0x0
@@ -52,13 +52,17 @@ CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
+CONFIG_MTD_M25P80=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_MUSEUM_IDS=y
+CONFIG_MTD_NAND_SLC_LPC32XX=y
+CONFIG_MTD_NAND_MLC_LPC32XX=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=1
 CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_AT25=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -79,16 +83,22 @@ CONFIG_LPC_ENET=y
 # CONFIG_NET_VENDOR_STMICRO is not set
 CONFIG_SMSC_PHY=y
 # CONFIG_WLAN is not set
+CONFIG_INPUT_MATRIXKMAP=y
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
 CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_LPC32XX=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_LPC32XX=y
+CONFIG_SERIO_LIBPS2=y
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_HS_LPC32XX=y
+CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
@@ -96,7 +106,8 @@ CONFIG_I2C_PNX=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_GPIO_SYSFS=y
-# CONFIG_HWMON is not set
+CONFIG_SENSORS_DS620=y
+CONFIG_SENSORS_MAX6639=y
 CONFIG_WATCHDOG=y
 CONFIG_PNX4008_WATCHDOG=y
 CONFIG_FB=y
@@ -133,6 +144,8 @@ CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_PCA9532=y
+CONFIG_LEDS_PCA9532_GPIO=y
 CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
@@ -146,10 +159,10 @@ CONFIG_RTC_DRV_DS1374=y
 CONFIG_RTC_DRV_PCF8563=y
 CONFIG_RTC_DRV_LPC32XX=y
 CONFIG_DMADEVICES=y
-CONFIG_AMBA_PL08X=y
 CONFIG_STAGING=y
-CONFIG_IIO=y
 CONFIG_LPC32XX_ADC=y
+CONFIG_MAX517=y
+CONFIG_IIO=y
 CONFIG_EXT2_FS=y
 CONFIG_AUTOFS4_FS=y
 CONFIG_MSDOS_FS=y
@@ -159,7 +172,6 @@ CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_WBUF_VERIFY=y
 CONFIG_CRAMFS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
index 5c903708974c52fb022175454363373141adbb43..b152de79fd95373e2f6fd8e34e66a4c360463c3b 100644 (file)
@@ -176,7 +176,6 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_MON=y
-CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_WDM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_LIBUSUAL=y
@@ -197,6 +196,7 @@ CONFIG_RTC_DRV_TWL4030=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT4_FS=y
 CONFIG_QUOTA=y
 CONFIG_QFMT_V2=y
 CONFIG_MSDOS_FS=y
index 68374ba6a943e9d029246d927b64a52913ea525e..c79f61faa3a55e81ae773b6d9d83532821b24c33 100644 (file)
@@ -243,7 +243,7 @@ typedef struct {
 
 #define ATOMIC64_INIT(i) { (i) }
 
-static inline u64 atomic64_read(atomic64_t *v)
+static inline u64 atomic64_read(const atomic64_t *v)
 {
        u64 result;
 
index 3d2220498abc2db2d98378c94a3309c71e91ccee..6ddbe446425e11524d927b5cd8b479bcd2419238 100644 (file)
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_CPU_USE_DOMAINS
-#define set_domain(x)                                  \
-       do {                                            \
-       __asm__ __volatile__(                           \
-       "mcr    p15, 0, %0, c3, c0      @ set domain"   \
-         : : "r" (x));                                 \
-       isb();                                          \
-       } while (0)
+static inline void set_domain(unsigned val)
+{
+       asm volatile(
+       "mcr    p15, 0, %0, c3, c0      @ set domain"
+         : : "r" (val));
+       isb();
+}
 
 #define modify_domain(dom,type)                                        \
        do {                                                    \
@@ -78,8 +78,8 @@
        } while (0)
 
 #else
-#define set_domain(x)          do { } while (0)
-#define modify_domain(dom,type)        do { } while (0)
+static inline void set_domain(unsigned val) { }
+static inline void modify_domain(unsigned dom, unsigned type)  { }
 #endif
 
 /*
index b79f8e97f7755f22d82ae20ee00442cd11f7af02..af7b0bda3355d9af850ae722b2b1f55277ef6e67 100644 (file)
@@ -148,7 +148,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define TIF_NOTIFY_RESUME      2       /* callback before returning to user */
 #define TIF_SYSCALL_TRACE      8
 #define TIF_SYSCALL_AUDIT      9
-#define TIF_SYSCALL_RESTARTSYS 10
 #define TIF_POLLING_NRFLAG     16
 #define TIF_USING_IWMMXT       17
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
@@ -164,11 +163,9 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT      (1 << TIF_USING_IWMMXT)
 #define _TIF_SECCOMP           (1 << TIF_SECCOMP)
-#define _TIF_SYSCALL_RESTARTSYS        (1 << TIF_SYSCALL_RESTARTSYS)
 
 /* Checks for any syscall work in entry-common.S */
-#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
-                          _TIF_SYSCALL_RESTARTSYS)
+#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
 
 /*
  * Change these and you break ASM code in entry-common.S
index 8349d4e97e2b8b9b7bb5672b2cf974c2cdb74fd0..16cedb42c0c39c0169008e45488b279cd9b32821 100644 (file)
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
 
-/*
- * No architecture-specific irq_finish function defined in arm/arch/irqs.h.
- */
-#ifndef irq_finish
-#define irq_finish(irq) do { } while (0)
-#endif
-
 unsigned long irq_err_count;
 
 int arch_show_interrupts(struct seq_file *p, int prec)
@@ -85,9 +78,6 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
                generic_handle_irq(irq);
        }
 
-       /* AT91 specific workaround */
-       irq_finish(irq);
-
        irq_exit();
        set_irq_regs(old_regs);
 }
index ba32b393b3f0c514c83799687348d52655bfe1da..38c1a3b103a0684b5b579bb74ca07f38bb91eb13 100644 (file)
@@ -187,8 +187,8 @@ void kprobe_arm_test_cases(void)
        TEST_BF_R ("mov pc, r",0,2f,"")
        TEST_BF_RR("mov pc, r",0,2f,", asl r",1,0,"")
        TEST_BB(   "sub pc, pc, #1b-2b+8")
-#if __LINUX_ARM_ARCH__ >= 6
-       TEST_BB(   "sub pc, pc, #1b-2b+8-2") /* UNPREDICTABLE before ARMv6 */
+#if __LINUX_ARM_ARCH__ == 6 && !defined(CONFIG_CPU_V7)
+       TEST_BB(   "sub pc, pc, #1b-2b+8-2") /* UNPREDICTABLE before and after ARMv6 */
 #endif
        TEST_BB_R( "sub pc, pc, r",14, 1f-2f+8,"")
        TEST_BB_R( "rsb pc, r",14,1f-2f+8,", pc")
index 186c8cb982c543a2cc1631796b34376151b33702..a02eada3aa5d06036027ac1241e652d5032781bd 100644 (file)
@@ -503,7 +503,7 @@ __hw_perf_event_init(struct perf_event *event)
             event_requires_mode_exclusion(&event->attr)) {
                pr_debug("ARM performance counters do not support "
                         "mode exclusion\n");
-               return -EPERM;
+               return -EOPNOTSUPP;
        }
 
        /*
index 5700a7ae7f0bc1511ae048d7a3f025c401e5729c..14e38261cd31db9d852db2eb0b8046251a04613d 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/regset.h>
 #include <linux/audit.h>
 #include <linux/tracehook.h>
-#include <linux/unistd.h>
 
 #include <asm/pgtable.h>
 #include <asm/traps.h>
@@ -918,8 +917,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
                audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0,
                                    regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
 
-       if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS))
-               scno = __NR_restart_syscall - __NR_SYSCALL_BASE;
        if (!test_thread_flag(TIF_SYSCALL_TRACE))
                return scno;
 
index fd2392a17ac1befb3464b5a0e77960a0f862b4ca..536c5d6b340b7fca2aee9c770000372c38be98bb 100644 (file)
@@ -27,6 +27,7 @@
  */
 #define SWI_SYS_SIGRETURN      (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
 #define SWI_SYS_RT_SIGRETURN   (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE))
+#define SWI_SYS_RESTART                (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)
 
 /*
  * With EABI, the syscall number has to be loaded into r7.
@@ -46,6 +47,18 @@ const unsigned long sigreturn_codes[7] = {
        MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
 };
 
+/*
+ * Either we support OABI only, or we have EABI with the OABI
+ * compat layer enabled.  In the later case we don't know if
+ * user space is EABI or not, and if not we must not clobber r7.
+ * Always using the OABI syscall solves that issue and works for
+ * all those cases.
+ */
+const unsigned long syscall_restart_code[2] = {
+       SWI_SYS_RESTART,        /* swi  __NR_restart_syscall */
+       0xe49df004,             /* ldr  pc, [sp], #4 */
+};
+
 /*
  * atomically swap in the new signal mask, and wait for a signal.
  */
@@ -592,10 +605,12 @@ static void do_signal(struct pt_regs *regs, int syscall)
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
-               case -ERESTART_RESTARTBLOCK:
                        regs->ARM_r0 = regs->ARM_ORIG_r0;
                        regs->ARM_pc = restart_addr;
                        break;
+               case -ERESTART_RESTARTBLOCK:
+                       regs->ARM_r0 = -EINTR;
+                       break;
                }
        }
 
@@ -611,14 +626,12 @@ static void do_signal(struct pt_regs *regs, int syscall)
                 * debugger has chosen to restart at a different PC.
                 */
                if (regs->ARM_pc == restart_addr) {
-                       if (retval == -ERESTARTNOHAND ||
-                           retval == -ERESTART_RESTARTBLOCK
+                       if (retval == -ERESTARTNOHAND
                            || (retval == -ERESTARTSYS
                                && !(ka.sa.sa_flags & SA_RESTART))) {
                                regs->ARM_r0 = -EINTR;
                                regs->ARM_pc = continue_addr;
                        }
-                       clear_thread_flag(TIF_SYSCALL_RESTARTSYS);
                }
 
                handle_signal(signr, &ka, &info, regs);
@@ -632,8 +645,29 @@ static void do_signal(struct pt_regs *regs, int syscall)
                 * ignore the restart.
                 */
                if (retval == -ERESTART_RESTARTBLOCK
-                   && regs->ARM_pc == restart_addr)
-                       set_thread_flag(TIF_SYSCALL_RESTARTSYS);
+                   && regs->ARM_pc == continue_addr) {
+                       if (thumb_mode(regs)) {
+                               regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE;
+                               regs->ARM_pc -= 2;
+                       } else {
+#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT)
+                               regs->ARM_r7 = __NR_restart_syscall;
+                               regs->ARM_pc -= 4;
+#else
+                               u32 __user *usp;
+
+                               regs->ARM_sp -= 4;
+                               usp = (u32 __user *)regs->ARM_sp;
+
+                               if (put_user(regs->ARM_pc, usp) == 0) {
+                                       regs->ARM_pc = KERN_RESTART_CODE;
+                               } else {
+                                       regs->ARM_sp += 4;
+                                       force_sigsegv(0, current);
+                               }
+#endif
+                       }
+               }
        }
 
        restore_saved_sigmask();
index 5ff067b7c7522f428b4343832ecb759b7ccf16de..6fcfe8398aa473051fbf72396986a84dc700978f 100644 (file)
@@ -8,5 +8,7 @@
  * published by the Free Software Foundation.
  */
 #define KERN_SIGRETURN_CODE    (CONFIG_VECTORS_BASE + 0x00000500)
+#define KERN_RESTART_CODE      (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
 
 extern const unsigned long sigreturn_codes[7];
+extern const unsigned long syscall_restart_code[2];
index 4928d89758f4ce0dea767acdf9fcf2299dff7833..3647170e9a16ba3aa8838218ed99e74dbc5b7c59 100644 (file)
@@ -820,6 +820,8 @@ void __init early_trap_init(void *vectors_base)
         */
        memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
               sigreturn_codes, sizeof(sigreturn_codes));
+       memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
+              syscall_restart_code, sizeof(syscall_restart_code));
 
        flush_icache_range(vectors, vectors + PAGE_SIZE);
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
index 43a31fb06318dc0a1213827a5069b73cac19f5a6..36ff15bbfdd4961afecfef9ea292c6445e9b3836 100644 (file)
@@ -183,7 +183,9 @@ SECTIONS
        }
 #endif
 
+#ifdef CONFIG_SMP
        PERCPU_SECTION(L1_CACHE_BYTES)
+#endif
 
 #ifdef CONFIG_XIP_KERNEL
        __data_loc = ALIGN(4);          /* location in binary */
index 19505c0a3f018225dcdc4935e089024e8d03d670..c8050b14e615ef0df3adbee08598b7aaf30a60ff 100644 (file)
@@ -29,12 +29,16 @@ comment "Atmel AT91 Processor"
 config SOC_AT91SAM9
        bool
        select CPU_ARM926T
+       select MULTI_IRQ_HANDLER
+       select SPARSE_IRQ
        select AT91_SAM9_TIME
        select AT91_SAM9_SMC
 
 config SOC_AT91RM9200
        bool "AT91RM9200"
        select CPU_ARM920T
+       select MULTI_IRQ_HANDLER
+       select SPARSE_IRQ
        select GENERIC_CLOCKEVENTS
        select HAVE_AT91_DBGU0
 
@@ -140,6 +144,8 @@ config ARCH_AT91SAM9G45
 config ARCH_AT91X40
        bool "AT91x40"
        depends on !MMU
+       select MULTI_IRQ_HANDLER
+       select SPARSE_IRQ
        select ARCH_USES_GETTIMEOFFSET
 
 endchoice
index 9e84fe4f2aaa00b2c23107f1e58a949afa7e68bb..30bb7332e30b99a8d45a7c20ed10d9f26ce4e9f2 100644 (file)
@@ -15,7 +15,9 @@ endif
 
 # Keep dtb files sorted alphabetically for each SoC
 # sam9260
+dtb-$(CONFIG_MACH_AT91SAM_DT) += aks-cdu.dtb
 dtb-$(CONFIG_MACH_AT91SAM_DT) += ethernut5.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += evk-pro3.dtb
 dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
 dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
 # sam9263
index 26917687fc30fd6b981181b79d8d338719d95305..6f50c6722276dcc73f8607b51132bfe40dd077b9 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/mach/map.h>
 #include <asm/system_misc.h>
 #include <mach/at91rm9200.h>
+#include <mach/at91_aic.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_st.h>
 #include <mach/cpu.h>
index e6b7d0533dd75dad4f6cee4f3458a2a6ddda6581..01fb7325fecce0ef9a015835ff846655b3b4af11 100644 (file)
@@ -41,8 +41,8 @@ static struct resource usbh_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_UHP,
-               .end    = AT91RM9200_ID_UHP,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -94,8 +94,8 @@ static struct resource udc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_UDP,
-               .end    = AT91RM9200_ID_UDP,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -145,8 +145,8 @@ static struct resource eth_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_EMAC,
-               .end    = AT91RM9200_ID_EMAC,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -305,8 +305,8 @@ static struct resource mmc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_MCI,
-               .end    = AT91RM9200_ID_MCI,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -488,8 +488,8 @@ static struct resource twi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_TWI,
-               .end    = AT91RM9200_ID_TWI,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -532,8 +532,8 @@ static struct resource spi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_SPI,
-               .end    = AT91RM9200_ID_SPI,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -598,18 +598,18 @@ static struct resource tcb0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_TC0,
-               .end    = AT91RM9200_ID_TC0,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
-               .start  = AT91RM9200_ID_TC1,
-               .end    = AT91RM9200_ID_TC1,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
-               .start  = AT91RM9200_ID_TC2,
-               .end    = AT91RM9200_ID_TC2,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -628,18 +628,18 @@ static struct resource tcb1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_TC3,
-               .end    = AT91RM9200_ID_TC3,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
-               .start  = AT91RM9200_ID_TC4,
-               .end    = AT91RM9200_ID_TC4,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
-               .start  = AT91RM9200_ID_TC5,
-               .end    = AT91RM9200_ID_TC5,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -673,8 +673,8 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -729,8 +729,8 @@ static struct resource ssc0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_SSC0,
-               .end    = AT91RM9200_ID_SSC0,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -771,8 +771,8 @@ static struct resource ssc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_SSC1,
-               .end    = AT91RM9200_ID_SSC1,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -813,8 +813,8 @@ static struct resource ssc2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_SSC2,
-               .end    = AT91RM9200_ID_SSC2,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -897,8 +897,8 @@ static struct resource dbgu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -935,8 +935,8 @@ static struct resource uart0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_US0,
-               .end    = AT91RM9200_ID_US0,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -984,8 +984,8 @@ static struct resource uart1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_US1,
-               .end    = AT91RM9200_ID_US1,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1035,8 +1035,8 @@ static struct resource uart2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_US2,
-               .end    = AT91RM9200_ID_US2,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1078,8 +1078,8 @@ static struct resource uart3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91RM9200_ID_US3,
-               .end    = AT91RM9200_ID_US3,
+               .start  = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
+               .end    = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
                .flags  = IORESOURCE_IRQ,
        },
 };
index 2b1e438ed87869320362678421486dc0caa058fd..30c7f26a4668c34e3739955a782ef3ec2befb978 100644 (file)
@@ -20,6 +20,7 @@
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 #include <mach/at91sam9260.h>
+#include <mach/at91_aic.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 
index 0ded951f785af1f31c7cba305f191a5f137ea096..7b9c2ba396edb854cfd78ddef676250a751e60bc 100644 (file)
@@ -45,8 +45,8 @@ static struct resource usbh_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_UHP,
-               .end    = AT91SAM9260_ID_UHP,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -98,8 +98,8 @@ static struct resource udc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_UDP,
-               .end    = AT91SAM9260_ID_UDP,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -149,8 +149,8 @@ static struct resource eth_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_EMAC,
-               .end    = AT91SAM9260_ID_EMAC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -223,8 +223,8 @@ static struct resource mmc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_MCI,
-               .end    = AT91SAM9260_ID_MCI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -305,8 +305,8 @@ static struct resource mmc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_MCI,
-               .end    = AT91SAM9260_ID_MCI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -496,8 +496,8 @@ static struct resource twi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_TWI,
-               .end    = AT91SAM9260_ID_TWI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -540,8 +540,8 @@ static struct resource spi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_SPI0,
-               .end    = AT91SAM9260_ID_SPI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -566,8 +566,8 @@ static struct resource spi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_SPI1,
-               .end    = AT91SAM9260_ID_SPI1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -652,18 +652,18 @@ static struct resource tcb0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_TC0,
-               .end    = AT91SAM9260_ID_TC0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
-               .start  = AT91SAM9260_ID_TC1,
-               .end    = AT91SAM9260_ID_TC1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
-               .start  = AT91SAM9260_ID_TC2,
-               .end    = AT91SAM9260_ID_TC2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -682,18 +682,18 @@ static struct resource tcb1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_TC3,
-               .end    = AT91SAM9260_ID_TC3,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
-               .start  = AT91SAM9260_ID_TC4,
-               .end    = AT91SAM9260_ID_TC4,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
-               .start  = AT91SAM9260_ID_TC5,
-               .end    = AT91SAM9260_ID_TC5,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -807,8 +807,8 @@ static struct resource ssc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_SSC,
-               .end    = AT91SAM9260_ID_SSC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -882,8 +882,8 @@ static struct resource dbgu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -920,8 +920,8 @@ static struct resource uart0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_US0,
-               .end    = AT91SAM9260_ID_US0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -971,8 +971,8 @@ static struct resource uart1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_US1,
-               .end    = AT91SAM9260_ID_US1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1014,8 +1014,8 @@ static struct resource uart2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_US2,
-               .end    = AT91SAM9260_ID_US2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1057,8 +1057,8 @@ static struct resource uart3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_US3,
-               .end    = AT91SAM9260_ID_US3,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1100,8 +1100,8 @@ static struct resource uart4_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_US4,
-               .end    = AT91SAM9260_ID_US4,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1138,8 +1138,8 @@ static struct resource uart5_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_US5,
-               .end    = AT91SAM9260_ID_US5,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1357,8 +1357,8 @@ static struct resource adc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9260_ID_ADC,
-               .end    = AT91SAM9260_ID_ADC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_ADC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_ADC,
                .flags  = IORESOURCE_IRQ,
        },
 };
index c77d503d09d1c2546a8e73a5ddccb246acb4ddcb..f40762c5fedee898fb836b24556f50499ee2858e 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/system_misc.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9261.h>
+#include <mach/at91_aic.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 
index 9295e90b08ff523fa93817ca9121eb15d9d5a2bb..8df5c1bdff92f1d1194fa9d64da61e2aa9bc2598 100644 (file)
@@ -45,8 +45,8 @@ static struct resource usbh_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_UHP,
-               .end    = AT91SAM9261_ID_UHP,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -98,8 +98,8 @@ static struct resource udc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_UDP,
-               .end    = AT91SAM9261_ID_UDP,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -148,8 +148,8 @@ static struct resource mmc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_MCI,
-               .end    = AT91SAM9261_ID_MCI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -310,8 +310,8 @@ static struct resource twi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_TWI,
-               .end    = AT91SAM9261_ID_TWI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -354,8 +354,8 @@ static struct resource spi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_SPI0,
-               .end    = AT91SAM9261_ID_SPI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -380,8 +380,8 @@ static struct resource spi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_SPI1,
-               .end    = AT91SAM9261_ID_SPI1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -468,8 +468,8 @@ static struct resource lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_LCDC,
-               .end    = AT91SAM9261_ID_LCDC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
                .flags  = IORESOURCE_IRQ,
        },
 #if defined(CONFIG_FB_INTSRAM)
@@ -566,18 +566,18 @@ static struct resource tcb_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_TC0,
-               .end    = AT91SAM9261_ID_TC0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
-               .start  = AT91SAM9261_ID_TC1,
-               .end    = AT91SAM9261_ID_TC1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
-               .start  = AT91SAM9261_ID_TC2,
-               .end    = AT91SAM9261_ID_TC2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -689,8 +689,8 @@ static struct resource ssc0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_SSC0,
-               .end    = AT91SAM9261_ID_SSC0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -731,8 +731,8 @@ static struct resource ssc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_SSC1,
-               .end    = AT91SAM9261_ID_SSC1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -773,8 +773,8 @@ static struct resource ssc2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_SSC2,
-               .end    = AT91SAM9261_ID_SSC2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -857,8 +857,8 @@ static struct resource dbgu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -895,8 +895,8 @@ static struct resource uart0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_US0,
-               .end    = AT91SAM9261_ID_US0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -938,8 +938,8 @@ static struct resource uart1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_US1,
-               .end    = AT91SAM9261_ID_US1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -981,8 +981,8 @@ static struct resource uart2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9261_ID_US2,
-               .end    = AT91SAM9261_ID_US2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
                .flags  = IORESOURCE_IRQ,
        },
 };
index ed91c7e9f7c20312ccc9f25564187c84f8e118af..84b38105231e91a52df082f3828f2042c1178201 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mach/map.h>
 #include <asm/system_misc.h>
 #include <mach/at91sam9263.h>
+#include <mach/at91_aic.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 
index 175e0009eaa9b886a90694dcf5cb1d880e2e38ad..eb6bbf86fb9f597cc7424a52b459bb04ecff2326 100644 (file)
@@ -44,8 +44,8 @@ static struct resource usbh_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_UHP,
-               .end    = AT91SAM9263_ID_UHP,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -104,8 +104,8 @@ static struct resource udc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_UDP,
-               .end    = AT91SAM9263_ID_UDP,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -155,8 +155,8 @@ static struct resource eth_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_EMAC,
-               .end    = AT91SAM9263_ID_EMAC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -229,8 +229,8 @@ static struct resource mmc0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_MCI0,
-               .end    = AT91SAM9263_ID_MCI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -254,8 +254,8 @@ static struct resource mmc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_MCI1,
-               .end    = AT91SAM9263_ID_MCI1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -567,8 +567,8 @@ static struct resource twi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_TWI,
-               .end    = AT91SAM9263_ID_TWI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -611,8 +611,8 @@ static struct resource spi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_SPI0,
-               .end    = AT91SAM9263_ID_SPI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -637,8 +637,8 @@ static struct resource spi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_SPI1,
-               .end    = AT91SAM9263_ID_SPI1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -725,8 +725,8 @@ static struct resource ac97_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_AC97C,
-               .end    = AT91SAM9263_ID_AC97C,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -776,8 +776,8 @@ static struct resource can_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_CAN,
-               .end    = AT91SAM9263_ID_CAN,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -816,8 +816,8 @@ static struct resource lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_LCDC,
-               .end    = AT91SAM9263_ID_LCDC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -883,8 +883,8 @@ struct resource isi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_ISI,
-               .end    = AT91SAM9263_ID_ISI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -940,8 +940,8 @@ static struct resource tcb_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_TCB,
-               .end    = AT91SAM9263_ID_TCB,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1108,8 +1108,8 @@ static struct resource pwm_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_PWMC,
-               .end    = AT91SAM9263_ID_PWMC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1161,8 +1161,8 @@ static struct resource ssc0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_SSC0,
-               .end    = AT91SAM9263_ID_SSC0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1203,8 +1203,8 @@ static struct resource ssc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_SSC1,
-               .end    = AT91SAM9263_ID_SSC1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1284,8 +1284,8 @@ static struct resource dbgu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1322,8 +1322,8 @@ static struct resource uart0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_US0,
-               .end    = AT91SAM9263_ID_US0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1365,8 +1365,8 @@ static struct resource uart1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_US1,
-               .end    = AT91SAM9263_ID_US1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1408,8 +1408,8 @@ static struct resource uart2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9263_ID_US2,
-               .end    = AT91SAM9263_ID_US2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
                .flags  = IORESOURCE_IRQ,
        },
 };
index a94758b42737a3d33a3cdce0bee439103ea8f7ab..ffc0957d7623ebe91319ab6a5810c0642ab328df 100644 (file)
@@ -137,7 +137,7 @@ static struct irqaction at91sam926x_pit_irq = {
        .name           = "at91_tick",
        .flags          = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
        .handler        = at91sam926x_pit_interrupt,
-       .irq            = AT91_ID_SYS,
+       .irq            = NR_IRQS_LEGACY + AT91_ID_SYS,
 };
 
 static void at91sam926x_pit_reset(void)
index 4792682d52b9962df1d227a3deb4370244260476..977127368a7dbd10d3785d4383840be2b72f840d 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mach/map.h>
 #include <asm/system_misc.h>
 #include <mach/at91sam9g45.h>
+#include <mach/at91_aic.h>
 #include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
index 933fc9afe7d091db78f5484d4ca331a50cb50716..40fb79df2de0b0ebb19c2d4eb4258490d9839cc9 100644 (file)
@@ -53,8 +53,8 @@ static struct resource hdmac_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_DMA,
-               .end    = AT91SAM9G45_ID_DMA,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -94,8 +94,8 @@ static struct resource usbh_ohci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_UHPHS,
-               .end    = AT91SAM9G45_ID_UHPHS,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -156,8 +156,8 @@ static struct resource usbh_ehci_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_UHPHS,
-               .end    = AT91SAM9G45_ID_UHPHS,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -213,8 +213,8 @@ static struct resource usba_udc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
-               .start  = AT91SAM9G45_ID_UDPHS,
-               .end    = AT91SAM9G45_ID_UDPHS,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -296,8 +296,8 @@ static struct resource eth_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_EMAC,
-               .end    = AT91SAM9G45_ID_EMAC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -370,8 +370,8 @@ static struct resource mmc0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_MCI0,
-               .end    = AT91SAM9G45_ID_MCI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -395,8 +395,8 @@ static struct resource mmc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_MCI1,
-               .end    = AT91SAM9G45_ID_MCI1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -645,8 +645,8 @@ static struct resource twi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_TWI0,
-               .end    = AT91SAM9G45_ID_TWI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -665,8 +665,8 @@ static struct resource twi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_TWI1,
-               .end    = AT91SAM9G45_ID_TWI1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -720,8 +720,8 @@ static struct resource spi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_SPI0,
-               .end    = AT91SAM9G45_ID_SPI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -746,8 +746,8 @@ static struct resource spi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_SPI1,
-               .end    = AT91SAM9G45_ID_SPI1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -834,8 +834,8 @@ static struct resource ac97_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_AC97C,
-               .end    = AT91SAM9G45_ID_AC97C,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -887,8 +887,8 @@ struct resource isi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_ISI,
-               .end    = AT91SAM9G45_ID_ISI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -979,8 +979,8 @@ static struct resource lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_LCDC,
-               .end    = AT91SAM9G45_ID_LCDC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1054,8 +1054,8 @@ static struct resource tcb0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_TCB,
-               .end    = AT91SAM9G45_ID_TCB,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1075,8 +1075,8 @@ static struct resource tcb1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_TCB,
-               .end    = AT91SAM9G45_ID_TCB,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1110,8 +1110,8 @@ static struct resource rtc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1147,8 +1147,8 @@ static struct resource tsadcc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_TSC,
-               .end    = AT91SAM9G45_ID_TSC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
                .flags  = IORESOURCE_IRQ,
        }
 };
@@ -1197,8 +1197,8 @@ static struct resource adc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_TSC,
-               .end    = AT91SAM9G45_ID_TSC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
                .flags  = IORESOURCE_IRQ,
        }
 };
@@ -1400,8 +1400,8 @@ static struct resource pwm_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_PWMC,
-               .end    = AT91SAM9G45_ID_PWMC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1453,8 +1453,8 @@ static struct resource ssc0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_SSC0,
-               .end    = AT91SAM9G45_ID_SSC0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1495,8 +1495,8 @@ static struct resource ssc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_SSC1,
-               .end    = AT91SAM9G45_ID_SSC1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1575,8 +1575,8 @@ static struct resource dbgu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1613,8 +1613,8 @@ static struct resource uart0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_US0,
-               .end    = AT91SAM9G45_ID_US0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1656,8 +1656,8 @@ static struct resource uart1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_US1,
-               .end    = AT91SAM9G45_ID_US1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1699,8 +1699,8 @@ static struct resource uart2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_US2,
-               .end    = AT91SAM9G45_ID_US2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1742,8 +1742,8 @@ static struct resource uart3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9G45_ID_US3,
-               .end    = AT91SAM9G45_ID_US3,
+               .start  = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
+               .end    = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
                .flags  = IORESOURCE_IRQ,
        },
 };
index e420085a57effa34a373b3aeeaca91185f248109..72ce50a50de5a278e21535422c1572bb95837a36 100644 (file)
@@ -19,6 +19,7 @@
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 #include <mach/at91sam9rl.h>
+#include <mach/at91_aic.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
 
index 9c0b1481a9a70c5d3ac6ebfc199c5d2e77ba1f46..f09fff932172ffec238c10714331d7c8970a53e1 100644 (file)
@@ -41,8 +41,8 @@ static struct resource hdmac_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
-               .start  = AT91SAM9RL_ID_DMA,
-               .end    = AT91SAM9RL_ID_DMA,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -84,8 +84,8 @@ static struct resource usba_udc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
-               .start  = AT91SAM9RL_ID_UDPHS,
-               .end    = AT91SAM9RL_ID_UDPHS,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -172,8 +172,8 @@ static struct resource mmc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_MCI,
-               .end    = AT91SAM9RL_ID_MCI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -339,8 +339,8 @@ static struct resource twi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_TWI0,
-               .end    = AT91SAM9RL_ID_TWI0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -383,8 +383,8 @@ static struct resource spi_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_SPI,
-               .end    = AT91SAM9RL_ID_SPI,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -452,8 +452,8 @@ static struct resource ac97_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_AC97C,
-               .end    = AT91SAM9RL_ID_AC97C,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -507,8 +507,8 @@ static struct resource lcdc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_LCDC,
-               .end    = AT91SAM9RL_ID_LCDC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -574,18 +574,18 @@ static struct resource tcb_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_TC0,
-               .end    = AT91SAM9RL_ID_TC0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
                .flags  = IORESOURCE_IRQ,
        },
        [2] = {
-               .start  = AT91SAM9RL_ID_TC1,
-               .end    = AT91SAM9RL_ID_TC1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
                .flags  = IORESOURCE_IRQ,
        },
        [3] = {
-               .start  = AT91SAM9RL_ID_TC2,
-               .end    = AT91SAM9RL_ID_TC2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -621,8 +621,8 @@ static struct resource tsadcc_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_TSC,
-               .end    = AT91SAM9RL_ID_TSC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
                .flags  = IORESOURCE_IRQ,
        }
 };
@@ -768,8 +768,8 @@ static struct resource pwm_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_PWMC,
-               .end    = AT91SAM9RL_ID_PWMC,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -821,8 +821,8 @@ static struct resource ssc0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_SSC0,
-               .end    = AT91SAM9RL_ID_SSC0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -863,8 +863,8 @@ static struct resource ssc1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_SSC1,
-               .end    = AT91SAM9RL_ID_SSC1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -943,8 +943,8 @@ static struct resource dbgu_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
+               .start  = NR_IRQS_LEGACY + AT91_ID_SYS,
+               .end    = NR_IRQS_LEGACY + AT91_ID_SYS,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -981,8 +981,8 @@ static struct resource uart0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_US0,
-               .end    = AT91SAM9RL_ID_US0,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1032,8 +1032,8 @@ static struct resource uart1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_US1,
-               .end    = AT91SAM9RL_ID_US1,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1075,8 +1075,8 @@ static struct resource uart2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_US2,
-               .end    = AT91SAM9RL_ID_US2,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -1118,8 +1118,8 @@ static struct resource uart3_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = AT91SAM9RL_ID_US3,
-               .end    = AT91SAM9RL_ID_US3,
+               .start  = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
+               .end    = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
                .flags  = IORESOURCE_IRQ,
        },
 };
index 1b144b4d3ce19da1ef7a580d2bbde299100eaa5f..477cf9d06672c7259cca0dab641bcb099de8e6b5 100644 (file)
@@ -312,8 +312,6 @@ static void __init at91sam9x5_map_io(void)
 
 void __init at91sam9x5_initialize(void)
 {
-       at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
-
        /* Register GPIO subsystem (using DT) */
        at91_gpio_init(NULL, 0);
 }
@@ -321,47 +319,9 @@ void __init at91sam9x5_initialize(void)
 /* --------------------------------------------------------------------
  *  Interrupt initialization
  * -------------------------------------------------------------------- */
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = {
-       7,      /* Advanced Interrupt Controller (FIQ) */
-       7,      /* System Peripherals */
-       1,      /* Parallel IO Controller A and B */
-       1,      /* Parallel IO Controller C and D */
-       4,      /* Soft Modem */
-       5,      /* USART 0 */
-       5,      /* USART 1 */
-       5,      /* USART 2 */
-       5,      /* USART 3 */
-       6,      /* Two-Wire Interface 0 */
-       6,      /* Two-Wire Interface 1 */
-       6,      /* Two-Wire Interface 2 */
-       0,      /* Multimedia Card Interface 0 */
-       5,      /* Serial Peripheral Interface 0 */
-       5,      /* Serial Peripheral Interface 1 */
-       5,      /* UART 0 */
-       5,      /* UART 1 */
-       0,      /* Timer Counter 0, 1, 2, 3, 4 and 5 */
-       0,      /* Pulse Width Modulation Controller */
-       0,      /* ADC Controller */
-       0,      /* DMA Controller 0 */
-       0,      /* DMA Controller 1 */
-       2,      /* USB Host High Speed port */
-       2,      /* USB Device High speed port */
-       3,      /* Ethernet MAC 0 */
-       3,      /* LDC Controller or Image Sensor Interface */
-       0,      /* Multimedia Card Interface 1 */
-       3,      /* Ethernet MAC 1 */
-       4,      /* Synchronous Serial Interface */
-       4,      /* CAN Controller 0 */
-       4,      /* CAN Controller 1 */
-       0,      /* Advanced Interrupt Controller (IRQ0) */
-};
 
 struct at91_init_soc __initdata at91sam9x5_soc = {
        .map_io = at91sam9x5_map_io,
-       .default_irq_priority = at91sam9x5_default_irq_priority,
        .register_clocks = at91sam9x5_register_clocks,
        .init = at91sam9x5_initialize,
 };
index d62fe090d814c4860403984e470d2f6ad919a79f..46090e642d8eb00b7fe93e05b70c9ea62dc9c8c3 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 #include <asm/proc-fns.h>
 #include <asm/system_misc.h>
 #include <asm/mach/arch.h>
 #include <mach/at91x40.h>
+#include <mach/at91_aic.h>
 #include <mach/at91_st.h>
 #include <mach/timex.h>
 #include "generic.h"
index 271f994314a469807f2d328f4c75418534d699dc..22d8856094f19a0b0c7512edc135de7425db4501 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <mach/board.h>
 #include <mach/cpu.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -91,6 +92,7 @@ MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = onearm_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = onearm_board_init,
index b7d8aa7b81e64baa60d6ea772a74a52c471d5228..de7be193181795cb210e5865df30e6fb8babb0d8 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -212,6 +213,7 @@ MACHINE_START(AFEB9260, "Custom afeb9260 board")
        /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = afeb9260_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = afeb9260_board_init,
index 29d3ef0a50fb9901ed71d6c27f7dd6de819950e8..477e708497bcfc47e4a225d189d767b07561d210 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 
 #include "sam9_smc.h"
@@ -188,6 +189,7 @@ MACHINE_START(CAM60, "KwikByte CAM60")
        /* Maintainer: KwikByte */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = cam60_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = cam60_board_init,
index 44328a6d46095027b75f903a11b7ec611c9043f5..a5b002f32a6162e98e6ae5335fcdbec2eb911332 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -158,6 +159,7 @@ MACHINE_START(CARMEVA, "Carmeva")
        /* Maintainer: Conitec Datasystems */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = carmeva_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = carmeva_board_init,
index 69951ec7dbf310dd5a4d800c90d9ae5dcc6adcff..ecbc13b594de05ed2877d27eab08b91db16cf475 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91sam9260_matrix.h>
 #include <mach/at91_matrix.h>
@@ -376,6 +377,7 @@ MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
        /* Maintainer: Eric Benard - EUKREA Electromatique */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = cpu9krea_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = cpu9krea_board_init,
index 895cf2dba612fe3a6c1ec0212ce7d1c45ff127cb..2e6d043c82f202e352b426e0ac699a74b15fbdcd 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91rm9200_mc.h>
 #include <mach/at91_ramc.h>
 #include <mach/cpu.h>
@@ -178,6 +179,7 @@ MACHINE_START(CPUAT91, "Eukrea")
        /* Maintainer: Eric Benard - EUKREA Electromatique */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = cpuat91_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = cpuat91_board_init,
index cd813361cd26be2d61a49de0f536f3be0ac1059d..462bc319cbc589b2bc86d80c4ebcce642ac7bc33 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -252,6 +253,7 @@ MACHINE_START(CSB337, "Cogent CSB337")
        /* Maintainer: Bill Gatliff */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = csb337_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = csb337_board_init,
index 7c8b05a57d7f5f9460e436f338b23668fe7ec577..872871ab11605e37dd35df90a85a7a8f8cb762c7 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -133,6 +134,7 @@ MACHINE_START(CSB637, "Cogent CSB637")
        /* Maintainer: Bill Gatliff */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = csb637_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = csb637_board_init,
index a1fce05aa7a5f7b64e8889f348934d3f75e5ee8a..e8f45c4e0ea8f01affd71c486d50ea1f42228e4c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/of_platform.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -53,6 +54,7 @@ DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = at91_dt_initialize,
        .init_irq       = at91_dt_init_irq,
        .init_machine   = at91_dt_device_init,
index d2023f27c65254f83113588a105d221ccfabf705..01f66e99ece73a875b3aa97b79c1af0ca54da58d 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include "generic.h"
 
 static void __init at91eb01_init_irq(void)
@@ -43,6 +44,7 @@ static void __init at91eb01_init_early(void)
 MACHINE_START(AT91EB01, "Atmel AT91 EB01")
        /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
        .timer          = &at91x40_timer,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = at91eb01_init_early,
        .init_irq       = at91eb01_init_irq,
 MACHINE_END
index bd10172979891c1aab6b139496b068500eedc30b..d1e1f3fc0a47a06d912eddc622048b0663c8be8d 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -118,6 +119,7 @@ static void __init eb9200_board_init(void)
 MACHINE_START(ATEB9200, "Embest ATEB9200")
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = eb9200_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = eb9200_board_init,
index 89cc3726a9ce1f3b57f5c589b5d495d1a6c5d4db..9c24cb25707c61dae73275d31c4c669af20528cd 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <mach/board.h>
 #include <mach/cpu.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -170,6 +171,7 @@ MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
        /* Maintainer: emQbit.com */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ecb_at91init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ecb_at91board_init,
index 558546cf63f492bf46d5b290b389e019f428244a..82bdfde3405f52d0ef1fd34507b12bd4bfe56466 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/mach/map.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91rm9200_mc.h>
 #include <mach/at91_ramc.h>
 #include <mach/cpu.h>
@@ -132,6 +133,7 @@ MACHINE_START(ECO920, "eco920")
        /* Maintainer: Sascha Hauer */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = eco920_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = eco920_board_init,
index 47658f78105db41fad698b7d438444f60c8f6cbf..6cc83a87d77cf9422e958f9526720842de343cb9 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include "generic.h"
 
@@ -160,6 +161,7 @@ MACHINE_START(FLEXIBITY, "Flexibity Connect")
        /* Maintainer: Maxim Osipov */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = flexibity_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = flexibity_board_init,
index 33411e6ecb1f1747f7431721003e4b722218bf57..69ab1247ef81263fb430de41d5c025263de5cb9e 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 
 #include "sam9_smc.h"
@@ -262,6 +263,7 @@ MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
        /* Maintainer: Sergio Tanzilli */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = foxg20_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = foxg20_board_init,
index 3e0dfa643a86e1714ad627638667a9df713375a7..a9d5e78118c5475a763bfb310a22b588d2c9ddc8 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/mach/arch.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/gsia18s.h>
 #include <mach/stamp9g20.h>
@@ -575,6 +576,7 @@ static void __init gsia18s_board_init(void)
 MACHINE_START(GSIA18S, "GS_IA18_S")
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = gsia18s_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = gsia18s_board_init,
index f260657f32bcf5881b3d2aa98fa9d442f992a4df..64c1dbf88a07bfe602f9c8c29071bff1ba5db774 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/cpu.h>
 
 #include "generic.h"
@@ -93,6 +94,7 @@ MACHINE_START(KAFA, "Sperry-Sun KAFA")
        /* Maintainer: Sergei Sharonov */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = kafa_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = kafa_board_init,
index ba39db5482b955617689e7f65adb39e245915738..5d96cb85175f9a6bce00c7b30ce12fa5d46b5821 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <mach/board.h>
 #include <mach/cpu.h>
+#include <mach/at91_aic.h>
 #include <mach/at91rm9200_mc.h>
 #include <mach/at91_ramc.h>
 
@@ -133,6 +134,7 @@ MACHINE_START(KB9200, "KB920x")
        /* Maintainer: KwikByte, Inc. */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = kb9202_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = kb9202_board_init,
index d2f4cc1617669e9d92729c47dde9d6c1bc84a0cf..18103c5d993ce24c148887d5bfc60331f4cb556d 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 
 #include "sam9_smc.h"
@@ -378,6 +379,7 @@ MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
        /* Maintainer: ADENEO */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = neocore926_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = neocore926_board_init,
index 7fe6383424213a173a9f5553077f3c468aff8945..9ca3e32c54cbb3b52acc0224625c5c83b8cecad3 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/mach/arch.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/stamp9g20.h>
 
@@ -218,6 +219,7 @@ MACHINE_START(PCONTROL_G20, "PControl G20")
        /* Maintainer: pgsellmann@portner-elektronik.at */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = pcontrol_g20_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = pcontrol_g20_board_init,
index b45c0a5d5ca7649c745d4718a329d0ee65fbdf20..127065504508c8fd5bffd4f00d778339fe497788 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91rm9200_mc.h>
 #include <mach/at91_ramc.h>
 
@@ -120,6 +121,7 @@ MACHINE_START(PICOTUX2XX, "picotux 200")
        /* Maintainer: Kleinhenz Elektronik GmbH */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = picotux200_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = picotux200_board_init,
index 0c61bf0d272c3b02215da56a7cfbdf7c2ce6a0fd..bf351e285422684cc71644e090ea428c766c556b 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 
@@ -258,6 +259,7 @@ MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index afd7a4713766cec538c1736daf0895f691d6ebf3..cc2bf9796073bcb096883059c7cced4153287a91 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91rm9200_mc.h>
 #include <mach/at91_ramc.h>
 
@@ -223,6 +224,7 @@ MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
        /* Maintainer: SAN People/Atmel */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = dk_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = dk_board_init,
index 2b15b8adec4ccb9c671fab7e2423a59f2860ad89..62e19e64c9d3f52dc0d5ca8e2470dfe9cfc1918e 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91rm9200_mc.h>
 #include <mach/at91_ramc.h>
 
@@ -190,6 +191,7 @@ MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
        /* Maintainer: SAN People/Atmel */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index 24ab9be7510fbe5f6cdd3296be794fd7affa8cdc..c3b43aefdb7597d2f71dc5e8e40e054019b891f6 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 
 #include <linux/gpio.h>
 
@@ -225,6 +226,7 @@ MACHINE_START(RSI_EWS, "RSI EWS")
        /* Maintainer: Josef Holzmayr <holzmayr@rsi-elektrotechnik.de> */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = rsi_ews_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = rsi_ews_board_init,
index cdd21f2595d2220de8fc828f636d240e0d0b1476..7bf6da70d7d56bbe735156f5c72add8a5441338b 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 
 #include "sam9_smc.h"
@@ -202,6 +203,7 @@ MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
        /* Maintainer: Olimex */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index 7b3c3913551a53ccc7a08eef94b5a18b7bba428b..889c1bf71eb596d2efd28fc76d086f2d87a42b9d 100644 (file)
@@ -42,6 +42,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 #include <mach/system_rev.h>
@@ -344,6 +345,7 @@ MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index 2736453821b0d55e9782d065107c176102ca4c35..2269be5fa3841075539fd106746ce7c7cc88776d 100644 (file)
@@ -46,6 +46,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 #include <mach/system_rev.h>
@@ -615,6 +616,7 @@ MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index 983cb98d2465c7253b2c9c2900de5379e2636979..82adf581afc2eb48868ea1d3198685bff22d457a 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 #include <mach/system_rev.h>
@@ -443,6 +444,7 @@ MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index 6860d3451100321a8bfd8930c6d5bc96e5fc3b9e..4ea4ee00364b44fd2fe1ef693d72e08e57a734e9 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/system_rev.h>
 
@@ -413,6 +414,7 @@ MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
@@ -422,6 +424,7 @@ MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index 63163dc7df46c4b416fadf21031c393716861fcc..3d48ec15468594f6b3fde5654f4f709eb4a4abea 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 #include <mach/system_rev.h>
@@ -503,6 +504,7 @@ MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index be3239f13daa64341598d1b5f33041ff44058eab..e7dc3ead7045f3f938c65729263a71be5050dafb 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 
@@ -319,6 +320,7 @@ MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
        /* Maintainer: Atmel */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index 9d446f1bb45fe6fcc91d78a35932bb56823e685e..a4e031a039fd50c0fd407ffc34d6ae9240070301 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 
 #include "sam9_smc.h"
@@ -178,6 +179,7 @@ static void __init snapper9260_board_init(void)
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = snapper9260_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = snapper9260_board_init,
index ee86f9d7ee72ed87bf408e273858be3dbe4586e1..29eae1626bf79ffa1ca4c4bf562d6ef255b81f82 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/mach/arch.h>
 
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 
 #include "sam9_smc.h"
@@ -287,6 +288,7 @@ MACHINE_START(PORTUXG20, "taskit PortuxG20")
        /* Maintainer: taskit GmbH */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = stamp9g20_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = portuxg20_board_init,
@@ -296,6 +298,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20")
        /* Maintainer: taskit GmbH */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = stamp9g20_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = stamp9g20evb_board_init,
index 95393fcaf199c9664bc6cafa8fafe17e826e5d92..c1476b9fe7b91a98ef279e4be2ecd250300bb1fc 100644 (file)
@@ -42,6 +42,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 
@@ -358,6 +359,7 @@ MACHINE_START(USB_A9263, "CALAO USB_A9263")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
@@ -367,6 +369,7 @@ MACHINE_START(USB_A9260, "CALAO USB_A9260")
        /* Maintainer: calao-systems */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
@@ -376,6 +379,7 @@ MACHINE_START(USB_A9G20, "CALAO USB_A92G0")
        /* Maintainer: Jean-Christophe PLAGNIOL-VILLARD */
        .timer          = &at91sam926x_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = ek_board_init,
index d56665ea4b55d3a8259228d8801fe20a547b9bab..516d340549d8db4c4ffe0a5ff461aee9cb7e6175 100644 (file)
@@ -44,6 +44,7 @@
 
 #include <mach/hardware.h>
 #include <mach/board.h>
+#include <mach/at91_aic.h>
 #include <mach/at91rm9200_mc.h>
 #include <mach/at91_ramc.h>
 #include <mach/cpu.h>
@@ -590,6 +591,7 @@ MACHINE_START(YL9200, "uCdragon YL-9200")
        /* Maintainer: S.Birtles */
        .timer          = &at91rm9200_timer,
        .map_io         = at91_map_io,
+       .handle_irq     = at91_aic_handle_irq,
        .init_early     = yl9200_init_early,
        .init_irq       = at91_init_irq_default,
        .init_machine   = yl9200_board_init,
index 0a60bf837037dd67382163c30f3290ed30acb9ae..f49650677653a0f0488e6c64346fcf07e46ae555 100644 (file)
@@ -29,6 +29,8 @@ extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 extern int  __init at91_aic_of_init(struct device_node *node,
                                    struct device_node *parent);
+extern int  __init at91_aic5_of_init(struct device_node *node,
+                                   struct device_node *parent);
 
 
  /* Timer */
index 325837a264c930fdbe1787d3ed2e61d3f75d1772..be42cf0e74bddd39ded6e1b54d7f17d351a24bc1 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/of_irq.h>
 #include <linux/of_gpio.h>
 
+#include <asm/mach/irq.h>
+
 #include <mach/hardware.h>
 #include <mach/at91_pio.h>
 
@@ -585,15 +587,14 @@ static struct irq_chip gpio_irqchip = {
 
 static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 {
+       struct irq_chip *chip = irq_desc_get_chip(desc);
        struct irq_data *idata = irq_desc_get_irq_data(desc);
-       struct irq_chip *chip = irq_data_get_irq_chip(idata);
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
        void __iomem    *pio = at91_gpio->regbase;
        unsigned long   isr;
        int             n;
 
-       /* temporarily mask (level sensitive) parent IRQ */
-       chip->irq_ack(idata);
+       chained_irq_enter(chip, desc);
        for (;;) {
                /* Reading ISR acks pending (edge triggered) GPIO interrupts.
                 * When there none are pending, we're finished unless we need
@@ -614,7 +615,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
                        n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
                }
        }
-       chip->irq_unmask(idata);
+       chained_irq_exit(chip, desc);
        /* now it may re-trigger */
 }
 
index 3045781c473f5d427e84e9ad83e51592c5e3d3da..eaea66197fa17f606e8f5d2228b5efa61e936c86 100644 (file)
@@ -23,12 +23,23 @@ extern void __iomem *at91_aic_base;
        __raw_readl(at91_aic_base + field)
 
 #define at91_aic_write(field, value) \
-       __raw_writel(value, at91_aic_base + field);
+       __raw_writel(value, at91_aic_base + field)
 #else
 .extern at91_aic_base
 #endif
 
+/* Number of irq lines managed by AIC */
+#define NR_AIC_IRQS    32
+#define NR_AIC5_IRQS   128
+
+#define AT91_AIC5_SSR          0x0                     /* Source Select Register [AIC5] */
+#define        AT91_AIC5_INTSEL_MSK    (0x7f << 0)             /* Interrupt Line Selection Mask */
+
+#define AT91_AIC_IRQ_MIN_PRIORITY      0
+#define AT91_AIC_IRQ_MAX_PRIORITY      7
+
 #define AT91_AIC_SMR(n)                ((n) * 4)               /* Source Mode Registers 0-31 */
+#define AT91_AIC5_SMR          0x4                     /* Source Mode Register [AIC5] */
 #define                AT91_AIC_PRIOR          (7 << 0)                /* Priority Level */
 #define                AT91_AIC_SRCTYPE        (3 << 5)                /* Interrupt Source Type */
 #define                        AT91_AIC_SRCTYPE_LOW            (0 << 5)
@@ -37,29 +48,52 @@ extern void __iomem *at91_aic_base;
 #define                        AT91_AIC_SRCTYPE_RISING         (3 << 5)
 
 #define AT91_AIC_SVR(n)                (0x80 + ((n) * 4))      /* Source Vector Registers 0-31 */
+#define AT91_AIC5_SVR          0x8                     /* Source Vector Register [AIC5] */
 #define AT91_AIC_IVR           0x100                   /* Interrupt Vector Register */
+#define AT91_AIC5_IVR          0x10                    /* Interrupt Vector Register [AIC5] */
 #define AT91_AIC_FVR           0x104                   /* Fast Interrupt Vector Register */
+#define AT91_AIC5_FVR          0x14                    /* Fast Interrupt Vector Register [AIC5] */
 #define AT91_AIC_ISR           0x108                   /* Interrupt Status Register */
+#define AT91_AIC5_ISR          0x18                    /* Interrupt Status Register [AIC5] */
 #define                AT91_AIC_IRQID          (0x1f << 0)             /* Current Interrupt Identifier */
 
 #define AT91_AIC_IPR           0x10c                   /* Interrupt Pending Register */
+#define AT91_AIC5_IPR0         0x20                    /* Interrupt Pending Register 0 [AIC5] */
+#define AT91_AIC5_IPR1         0x24                    /* Interrupt Pending Register 1 [AIC5] */
+#define AT91_AIC5_IPR2         0x28                    /* Interrupt Pending Register 2 [AIC5] */
+#define AT91_AIC5_IPR3         0x2c                    /* Interrupt Pending Register 3 [AIC5] */
 #define AT91_AIC_IMR           0x110                   /* Interrupt Mask Register */
+#define AT91_AIC5_IMR          0x30                    /* Interrupt Mask Register [AIC5] */
 #define AT91_AIC_CISR          0x114                   /* Core Interrupt Status Register */
+#define AT91_AIC5_CISR         0x34                    /* Core Interrupt Status Register [AIC5] */
 #define                AT91_AIC_NFIQ           (1 << 0)                /* nFIQ Status */
 #define                AT91_AIC_NIRQ           (1 << 1)                /* nIRQ Status */
 
 #define AT91_AIC_IECR          0x120                   /* Interrupt Enable Command Register */
+#define AT91_AIC5_IECR         0x40                    /* Interrupt Enable Command Register [AIC5] */
 #define AT91_AIC_IDCR          0x124                   /* Interrupt Disable Command Register */
+#define AT91_AIC5_IDCR         0x44                    /* Interrupt Disable Command Register [AIC5] */
 #define AT91_AIC_ICCR          0x128                   /* Interrupt Clear Command Register */
+#define AT91_AIC5_ICCR         0x48                    /* Interrupt Clear Command Register [AIC5] */
 #define AT91_AIC_ISCR          0x12c                   /* Interrupt Set Command Register */
+#define AT91_AIC5_ISCR         0x4c                    /* Interrupt Set Command Register [AIC5] */
 #define AT91_AIC_EOICR         0x130                   /* End of Interrupt Command Register */
+#define AT91_AIC5_EOICR                0x38                    /* End of Interrupt Command Register [AIC5] */
 #define AT91_AIC_SPU           0x134                   /* Spurious Interrupt Vector Register */
+#define AT91_AIC5_SPU          0x3c                    /* Spurious Interrupt Vector Register [AIC5] */
 #define AT91_AIC_DCR           0x138                   /* Debug Control Register */
+#define AT91_AIC5_DCR          0x6c                    /* Debug Control Register [AIC5] */
 #define                AT91_AIC_DCR_PROT       (1 << 0)                /* Protection Mode */
 #define                AT91_AIC_DCR_GMSK       (1 << 1)                /* General Mask */
 
 #define AT91_AIC_FFER          0x140                   /* Fast Forcing Enable Register [SAM9 only] */
+#define AT91_AIC5_FFER         0x50                    /* Fast Forcing Enable Register [AIC5] */
 #define AT91_AIC_FFDR          0x144                   /* Fast Forcing Disable Register [SAM9 only] */
+#define AT91_AIC5_FFDR         0x54                    /* Fast Forcing Disable Register [AIC5] */
 #define AT91_AIC_FFSR          0x148                   /* Fast Forcing Status Register [SAM9 only] */
+#define AT91_AIC5_FFSR         0x58                    /* Fast Forcing Status Register [AIC5] */
+
+void at91_aic_handle_irq(struct pt_regs *regs);
+void at91_aic5_handle_irq(struct pt_regs *regs);
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/at91_spi.h b/arch/arm/mach-at91/include/mach/at91_spi.h
deleted file mode 100644 (file)
index 2f6ba0c..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_spi.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Serial Peripheral Interface (SPI) registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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 AT91_SPI_H
-#define AT91_SPI_H
-
-#define AT91_SPI_CR                    0x00            /* Control Register */
-#define                AT91_SPI_SPIEN          (1 <<  0)               /* SPI Enable */
-#define                AT91_SPI_SPIDIS         (1 <<  1)               /* SPI Disable */
-#define                AT91_SPI_SWRST          (1 <<  7)               /* SPI Software Reset */
-#define                AT91_SPI_LASTXFER       (1 << 24)               /* Last Transfer [SAM9261 only] */
-
-#define AT91_SPI_MR                    0x04            /* Mode Register */
-#define                AT91_SPI_MSTR           (1    <<  0)            /* Master/Slave Mode */
-#define                AT91_SPI_PS             (1    <<  1)            /* Peripheral Select */
-#define                        AT91_SPI_PS_FIXED       (0 << 1)
-#define                        AT91_SPI_PS_VARIABLE    (1 << 1)
-#define                AT91_SPI_PCSDEC         (1    <<  2)            /* Chip Select Decode */
-#define                AT91_SPI_DIV32          (1    <<  3)            /* Clock Selection [AT91RM9200 only] */
-#define                AT91_SPI_MODFDIS        (1    <<  4)            /* Mode Fault Detection */
-#define                AT91_SPI_LLB            (1    <<  7)            /* Local Loopback Enable */
-#define                AT91_SPI_PCS            (0xf  << 16)            /* Peripheral Chip Select */
-#define                AT91_SPI_DLYBCS         (0xff << 24)            /* Delay Between Chip Selects */
-
-#define AT91_SPI_RDR           0x08                    /* Receive Data Register */
-#define                AT91_SPI_RD             (0xffff <<  0)          /* Receive Data */
-#define                AT91_SPI_PCS            (0xf    << 16)          /* Peripheral Chip Select */
-
-#define AT91_SPI_TDR           0x0c                    /* Transmit Data Register */
-#define                AT91_SPI_TD             (0xffff <<  0)          /* Transmit Data */
-#define                AT91_SPI_PCS            (0xf    << 16)          /* Peripheral Chip Select */
-#define                AT91_SPI_LASTXFER       (1      << 24)          /* Last Transfer [SAM9261 only] */
-
-#define AT91_SPI_SR            0x10                    /* Status Register */
-#define                AT91_SPI_RDRF           (1 <<  0)               /* Receive Data Register Full */
-#define                AT91_SPI_TDRE           (1 <<  1)               /* Transmit Data Register Full */
-#define                AT91_SPI_MODF           (1 <<  2)               /* Mode Fault Error */
-#define                AT91_SPI_OVRES          (1 <<  3)               /* Overrun Error Status */
-#define                AT91_SPI_ENDRX          (1 <<  4)               /* End of RX buffer */
-#define                AT91_SPI_ENDTX          (1 <<  5)               /* End of TX buffer */
-#define                AT91_SPI_RXBUFF         (1 <<  6)               /* RX Buffer Full */
-#define                AT91_SPI_TXBUFE         (1 <<  7)               /* TX Buffer Empty */
-#define                AT91_SPI_NSSR           (1 <<  8)               /* NSS Rising [SAM9261 only] */
-#define                AT91_SPI_TXEMPTY        (1 <<  9)               /* Transmission Register Empty [SAM9261 only] */
-#define                AT91_SPI_SPIENS         (1 << 16)               /* SPI Enable Status */
-
-#define AT91_SPI_IER           0x14                    /* Interrupt Enable Register */
-#define AT91_SPI_IDR           0x18                    /* Interrupt Disable Register */
-#define AT91_SPI_IMR           0x1c                    /* Interrupt Mask Register */
-
-#define AT91_SPI_CSR(n)                (0x30 + ((n) * 4))      /* Chip Select Registers 0-3 */
-#define                AT91_SPI_CPOL           (1    <<  0)            /* Clock Polarity */
-#define                AT91_SPI_NCPHA          (1    <<  1)            /* Clock Phase */
-#define                AT91_SPI_CSAAT          (1    <<  3)            /* Chip Select Active After Transfer [SAM9261 only] */
-#define                AT91_SPI_BITS           (0xf  <<  4)            /* Bits Per Transfer */
-#define                        AT91_SPI_BITS_8         (0 << 4)
-#define                        AT91_SPI_BITS_9         (1 << 4)
-#define                        AT91_SPI_BITS_10        (2 << 4)
-#define                        AT91_SPI_BITS_11        (3 << 4)
-#define                        AT91_SPI_BITS_12        (4 << 4)
-#define                        AT91_SPI_BITS_13        (5 << 4)
-#define                        AT91_SPI_BITS_14        (6 << 4)
-#define                        AT91_SPI_BITS_15        (7 << 4)
-#define                        AT91_SPI_BITS_16        (8 << 4)
-#define                AT91_SPI_SCBR           (0xff <<  8)            /* Serial Clock Baud Rate */
-#define                AT91_SPI_DLYBS          (0xff << 16)            /* Delay before SPCK */
-#define                AT91_SPI_DLYBCT         (0xff << 24)            /* Delay between Consecutive Transfers */
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at91_ssc.h b/arch/arm/mach-at91/include/mach/at91_ssc.h
deleted file mode 100644 (file)
index a81114c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_ssc.h
- *
- * Copyright (C) SAN People
- *
- * Serial Synchronous Controller (SSC) registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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 AT91_SSC_H
-#define AT91_SSC_H
-
-#define AT91_SSC_CR            0x00    /* Control Register */
-#define                AT91_SSC_RXEN           (1 <<  0)       /* Receive Enable */
-#define                AT91_SSC_RXDIS          (1 <<  1)       /* Receive Disable */
-#define                AT91_SSC_TXEN           (1 <<  8)       /* Transmit Enable */
-#define                AT91_SSC_TXDIS          (1 <<  9)       /* Transmit Disable */
-#define                AT91_SSC_SWRST          (1 << 15)       /* Software Reset */
-
-#define AT91_SSC_CMR           0x04    /* Clock Mode Register */
-#define                AT91_SSC_CMR_DIV        (0xfff << 0)    /* Clock Divider */
-
-#define AT91_SSC_RCMR          0x10    /* Receive Clock Mode Register */
-#define                AT91_SSC_CKS            (3    <<  0)    /* Clock Selection */
-#define                        AT91_SSC_CKS_DIV                (0 << 0)
-#define                        AT91_SSC_CKS_CLOCK              (1 << 0)
-#define                        AT91_SSC_CKS_PIN                (2 << 0)
-#define                AT91_SSC_CKO            (7    <<  2)    /* Clock Output Mode Selection */
-#define                        AT91_SSC_CKO_NONE               (0 << 2)
-#define                        AT91_SSC_CKO_CONTINUOUS         (1 << 2)
-#define                AT91_SSC_CKI            (1    <<  5)    /* Clock Inversion */
-#define                        AT91_SSC_CKI_FALLING            (0 << 5)
-#define                        AT91_SSC_CK_RISING              (1 << 5)
-#define                AT91_SSC_CKG            (1    <<  6)    /* Receive Clock Gating Selection [AT91SAM9261 only] */
-#define                        AT91_SSC_CKG_NONE               (0 << 6)
-#define                        AT91_SSC_CKG_RFLOW              (1 << 6)
-#define                        AT91_SSC_CKG_RFHIGH             (2 << 6)
-#define                AT91_SSC_START          (0xf  <<  8)    /* Start Selection */
-#define                        AT91_SSC_START_CONTINUOUS       (0 << 8)
-#define                        AT91_SSC_START_TX_RX            (1 << 8)
-#define                        AT91_SSC_START_LOW_RF           (2 << 8)
-#define                        AT91_SSC_START_HIGH_RF          (3 << 8)
-#define                        AT91_SSC_START_FALLING_RF       (4 << 8)
-#define                        AT91_SSC_START_RISING_RF        (5 << 8)
-#define                        AT91_SSC_START_LEVEL_RF         (6 << 8)
-#define                        AT91_SSC_START_EDGE_RF          (7 << 8)
-#define                AT91_SSC_STOP           (1    << 12)    /* Receive Stop Selection [AT91SAM9261 only] */
-#define                AT91_SSC_STTDLY         (0xff << 16)    /* Start Delay */
-#define                AT91_SSC_PERIOD         (0xff << 24)    /* Period Divider Selection */
-
-#define AT91_SSC_RFMR          0x14    /* Receive Frame Mode Register */
-#define                AT91_SSC_DATALEN        (0x1f <<  0)    /* Data Length */
-#define                AT91_SSC_LOOP           (1    <<  5)    /* Loop Mode */
-#define                AT91_SSC_MSBF           (1    <<  7)    /* Most Significant Bit First */
-#define                AT91_SSC_DATNB          (0xf  <<  8)    /* Data Number per Frame */
-#define                AT91_SSC_FSLEN          (0xf  << 16)    /* Frame Sync Length */
-#define                AT91_SSC_FSOS           (7    << 20)    /* Frame Sync Output Selection */
-#define                        AT91_SSC_FSOS_NONE              (0 << 20)
-#define                        AT91_SSC_FSOS_NEGATIVE          (1 << 20)
-#define                        AT91_SSC_FSOS_POSITIVE          (2 << 20)
-#define                        AT91_SSC_FSOS_LOW               (3 << 20)
-#define                        AT91_SSC_FSOS_HIGH              (4 << 20)
-#define                        AT91_SSC_FSOS_TOGGLE            (5 << 20)
-#define                AT91_SSC_FSEDGE         (1    << 24)    /* Frame Sync Edge Detection */
-#define                        AT91_SSC_FSEDGE_POSITIVE        (0 << 24)
-#define                        AT91_SSC_FSEDGE_NEGATIVE        (1 << 24)
-
-#define AT91_SSC_TCMR          0x18    /* Transmit Clock Mode Register */
-#define AT91_SSC_TFMR          0x1c    /* Transmit Fram Mode Register */
-#define                AT91_SSC_DATDEF         (1 <<  5)       /* Data Default Value */
-#define                AT91_SSC_FSDEN          (1 << 23)       /* Frame Sync Data Enable */
-
-#define AT91_SSC_RHR           0x20    /* Receive Holding Register */
-#define AT91_SSC_THR           0x24    /* Transmit Holding Register */
-#define AT91_SSC_RSHR          0x30    /* Receive Sync Holding Register */
-#define AT91_SSC_TSHR          0x34    /* Transmit Sync Holding Register */
-
-#define AT91_SSC_RC0R          0x38    /* Receive Compare 0 Register [AT91SAM9261 only] */
-#define AT91_SSC_RC1R          0x3c    /* Receive Compare 1 Register [AT91SAM9261 only] */
-
-#define AT91_SSC_SR            0x40    /* Status Register */
-#define                AT91_SSC_TXRDY          (1 <<  0)       /* Transmit Ready */
-#define                AT91_SSC_TXEMPTY        (1 <<  1)       /* Transmit Empty */
-#define                AT91_SSC_ENDTX          (1 <<  2)       /* End of Transmission */
-#define                AT91_SSC_TXBUFE         (1 <<  3)       /* Transmit Buffer Empty */
-#define                AT91_SSC_RXRDY          (1 <<  4)       /* Receive Ready */
-#define                AT91_SSC_OVRUN          (1 <<  5)       /* Receive Overrun */
-#define                AT91_SSC_ENDRX          (1 <<  6)       /* End of Reception */
-#define                AT91_SSC_RXBUFF         (1 <<  7)       /* Receive Buffer Full */
-#define                AT91_SSC_CP0            (1 <<  8)       /* Compare 0 [AT91SAM9261 only] */
-#define                AT91_SSC_CP1            (1 <<  9)       /* Compare 1 [AT91SAM9261 only] */
-#define                AT91_SSC_TXSYN          (1 << 10)       /* Transmit Sync */
-#define                AT91_SSC_RXSYN          (1 << 11)       /* Receive Sync */
-#define                AT91_SSC_TXENA          (1 << 16)       /* Transmit Enable */
-#define                AT91_SSC_RXENA          (1 << 17)       /* Receive Enable */
-
-#define AT91_SSC_IER           0x44    /* Interrupt Enable Register */
-#define AT91_SSC_IDR           0x48    /* Interrupt Disable Register */
-#define AT91_SSC_IMR           0x4c    /* Interrupt Mask Register */
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/entry-macro.S b/arch/arm/mach-at91/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 903bf20..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/entry-macro.S
- *
- *  Copyright (C) 2003-2005 SAN People
- *
- * Low-level IRQ helper macros for AT91RM9200 platforms
- *
- * 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 <mach/hardware.h>
-#include <mach/at91_aic.h>
-
-       .macro  get_irqnr_preamble, base, tmp
-       ldr     \base, =at91_aic_base           @ base virtual address of AIC peripheral
-       ldr     \base, [\base]
-       .endm
-
-       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-       ldr     \irqnr, [\base, #AT91_AIC_IVR]          @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
-       ldr     \irqstat, [\base, #AT91_AIC_ISR]        @ read interrupt source number
-       teq     \irqstat, #0                            @ ISR is 0 when no current interrupt, or spurious interrupt
-       streq   \tmp, [\base, #AT91_AIC_EOICR]          @ not going to be handled further, then ACK it now.
-       .endm
-
diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
deleted file mode 100644 (file)
index ac8b7df..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/irqs.h
- *
- *  Copyright (C) 2004 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H
-
-#include <linux/io.h>
-#include <mach/at91_aic.h>
-
-#define NR_AIC_IRQS 32
-
-
-/*
- * Acknowledge interrupt with AIC after interrupt has been handled.
- *   (by kernel/irq.c)
- */
-#define irq_finish(irq) do { at91_aic_write(AT91_AIC_EOICR, 0); } while (0)
-
-
-/*
- * IRQ interrupt symbols are the AT91xxx_ID_* symbols
- * for IRQs handled directly through the AIC, or else the AT91_PIN_*
- * symbols in gpio.h for ones handled indirectly as GPIOs.
- * We make provision for 5 banks of GPIO.
- */
-#define        NR_IRQS         (NR_AIC_IRQS + (5 * 32))
-
-/* FIQ is AIC source 0. */
-#define FIQ_START AT91_ID_FIQ
-
-#endif
index cfcfcbe362699d1ed04be46e2d9680bc89917e58..1e02c0e49dccb76949be0fc9d855a5a3bb3504bc 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/bitmap.h>
 #include <linux/types.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/irqdomain.h>
 #include <linux/err.h>
+#include <linux/slab.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/setup.h>
 
+#include <asm/exception.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 
+#include <mach/at91_aic.h>
+
 void __iomem *at91_aic_base;
 static struct irq_domain *at91_aic_domain;
 static struct device_node *at91_aic_np;
+static unsigned int n_irqs = NR_AIC_IRQS;
+static unsigned long at91_aic_caps = 0;
+
+/* AIC5 introduces a Source Select Register */
+#define AT91_AIC_CAP_AIC5      (1 << 0)
+#define has_aic5()             (at91_aic_caps & AT91_AIC_CAP_AIC5)
+
+#ifdef CONFIG_PM
+
+static unsigned long *wakeups;
+static unsigned long *backups;
+
+#define set_backup(bit) set_bit(bit, backups)
+#define clear_backup(bit) clear_bit(bit, backups)
+
+static int at91_aic_pm_init(void)
+{
+       backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
+       if (!backups)
+               return -ENOMEM;
+
+       wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
+       if (!wakeups) {
+               kfree(backups);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int at91_aic_set_wake(struct irq_data *d, unsigned value)
+{
+       if (unlikely(d->hwirq >= n_irqs))
+               return -EINVAL;
+
+       if (value)
+               set_bit(d->hwirq, wakeups);
+       else
+               clear_bit(d->hwirq, wakeups);
+
+       return 0;
+}
+
+void at91_irq_suspend(void)
+{
+       int i = 0, bit;
+
+       if (has_aic5()) {
+               /* disable enabled irqs */
+               while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IDCR, 1);
+                       i = bit;
+               }
+               /* enable wakeup irqs */
+               i = 0;
+               while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IECR, 1);
+                       i = bit;
+               }
+       } else {
+               at91_aic_write(AT91_AIC_IDCR, *backups);
+               at91_aic_write(AT91_AIC_IECR, *wakeups);
+       }
+}
+
+void at91_irq_resume(void)
+{
+       int i = 0, bit;
+
+       if (has_aic5()) {
+               /* disable wakeup irqs */
+               while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IDCR, 1);
+                       i = bit;
+               }
+               /* enable irqs disabled for suspend */
+               i = 0;
+               while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IECR, 1);
+                       i = bit;
+               }
+       } else {
+               at91_aic_write(AT91_AIC_IDCR, *wakeups);
+               at91_aic_write(AT91_AIC_IECR, *backups);
+       }
+}
+
+#else
+static inline int at91_aic_pm_init(void)
+{
+       return 0;
+}
+
+#define set_backup(bit)
+#define clear_backup(bit)
+#define at91_aic_set_wake      NULL
+
+#endif /* CONFIG_PM */
+
+asmlinkage void __exception_irq_entry
+at91_aic_handle_irq(struct pt_regs *regs)
+{
+       u32 irqnr;
+       u32 irqstat;
+
+       irqnr = at91_aic_read(AT91_AIC_IVR);
+       irqstat = at91_aic_read(AT91_AIC_ISR);
+
+       /*
+        * ISR value is 0 when there is no current interrupt or when there is
+        * a spurious interrupt
+        */
+       if (!irqstat)
+               at91_aic_write(AT91_AIC_EOICR, 0);
+       else
+               handle_IRQ(irqnr, regs);
+}
+
+asmlinkage void __exception_irq_entry
+at91_aic5_handle_irq(struct pt_regs *regs)
+{
+       u32 irqnr;
+       u32 irqstat;
+
+       irqnr = at91_aic_read(AT91_AIC5_IVR);
+       irqstat = at91_aic_read(AT91_AIC5_ISR);
+
+       if (!irqstat)
+               at91_aic_write(AT91_AIC5_EOICR, 0);
+       else
+               handle_IRQ(irqnr, regs);
+}
 
 static void at91_aic_mask_irq(struct irq_data *d)
 {
        /* Disable interrupt on AIC */
        at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
+       /* Update ISR cache */
+       clear_backup(d->hwirq);
+}
+
+static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d)
+{
+       /* Disable interrupt on AIC5 */
+       at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
+       at91_aic_write(AT91_AIC5_IDCR, 1);
+       /* Update ISR cache */
+       clear_backup(d->hwirq);
 }
 
 static void at91_aic_unmask_irq(struct irq_data *d)
 {
        /* Enable interrupt on AIC */
        at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
+       /* Update ISR cache */
+       set_backup(d->hwirq);
+}
+
+static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d)
+{
+       /* Enable interrupt on AIC5 */
+       at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
+       at91_aic_write(AT91_AIC5_IECR, 1);
+       /* Update ISR cache */
+       set_backup(d->hwirq);
 }
 
-unsigned int at91_extern_irq;
+static void at91_aic_eoi(struct irq_data *d)
+{
+       /*
+        * Mark end-of-interrupt on AIC, the controller doesn't care about
+        * the value written. Moreover it's a write-only register.
+        */
+       at91_aic_write(AT91_AIC_EOICR, 0);
+}
+
+static void __maybe_unused at91_aic5_eoi(struct irq_data *d)
+{
+       at91_aic_write(AT91_AIC5_EOICR, 0);
+}
 
-#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
+unsigned long *at91_extern_irq;
 
-static int at91_aic_set_type(struct irq_data *d, unsigned type)
+#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
+
+static int at91_aic_compute_srctype(struct irq_data *d, unsigned type)
 {
-       unsigned int smr, srctype;
+       int srctype;
 
        switch (type) {
        case IRQ_TYPE_LEVEL_HIGH:
@@ -74,65 +255,51 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
                if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_LOW;
                else
-                       return -EINVAL;
+                       srctype = -EINVAL;
                break;
        case IRQ_TYPE_EDGE_FALLING:
                if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_FALLING;
                else
-                       return -EINVAL;
+                       srctype = -EINVAL;
                break;
        default:
-               return -EINVAL;
+               srctype = -EINVAL;
        }
 
-       smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
-       at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
-       return 0;
+       return srctype;
 }
 
-#ifdef CONFIG_PM
-
-static u32 wakeups;
-static u32 backups;
-
-static int at91_aic_set_wake(struct irq_data *d, unsigned value)
+static int at91_aic_set_type(struct irq_data *d, unsigned type)
 {
-       if (unlikely(d->hwirq >= NR_AIC_IRQS))
-               return -EINVAL;
-
-       if (value)
-               wakeups |= (1 << d->hwirq);
-       else
-               wakeups &= ~(1 << d->hwirq);
+       unsigned int smr;
+       int srctype;
+
+       srctype = at91_aic_compute_srctype(d, type);
+       if (srctype < 0)
+               return srctype;
+
+       if (has_aic5()) {
+               at91_aic_write(AT91_AIC5_SSR,
+                              d->hwirq & AT91_AIC5_INTSEL_MSK);
+               smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE;
+               at91_aic_write(AT91_AIC5_SMR, smr | srctype);
+       } else {
+               smr = at91_aic_read(AT91_AIC_SMR(d->hwirq))
+                     & ~AT91_AIC_SRCTYPE;
+               at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
+       }
 
        return 0;
 }
 
-void at91_irq_suspend(void)
-{
-       backups = at91_aic_read(AT91_AIC_IMR);
-       at91_aic_write(AT91_AIC_IDCR, backups);
-       at91_aic_write(AT91_AIC_IECR, wakeups);
-}
-
-void at91_irq_resume(void)
-{
-       at91_aic_write(AT91_AIC_IDCR, wakeups);
-       at91_aic_write(AT91_AIC_IECR, backups);
-}
-
-#else
-#define at91_aic_set_wake      NULL
-#endif
-
 static struct irq_chip at91_aic_chip = {
        .name           = "AIC",
-       .irq_ack        = at91_aic_mask_irq,
        .irq_mask       = at91_aic_mask_irq,
        .irq_unmask     = at91_aic_unmask_irq,
        .irq_set_type   = at91_aic_set_type,
        .irq_set_wake   = at91_aic_set_wake,
+       .irq_eoi        = at91_aic_eoi,
 };
 
 static void __init at91_aic_hw_init(unsigned int spu_vector)
@@ -161,41 +328,172 @@ static void __init at91_aic_hw_init(unsigned int spu_vector)
        at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
 }
 
+static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
+{
+       int i;
+
+       /*
+        * Perform 8 End Of Interrupt Command to make sure AIC
+        * will not Lock out nIRQ
+        */
+       for (i = 0; i < 8; i++)
+               at91_aic_write(AT91_AIC5_EOICR, 0);
+
+       /*
+        * Spurious Interrupt ID in Spurious Vector Register.
+        * When there is no current interrupt, the IRQ Vector Register
+        * reads the value stored in AIC_SPU
+        */
+       at91_aic_write(AT91_AIC5_SPU, spu_vector);
+
+       /* No debugging in AIC: Debug (Protect) Control Register */
+       at91_aic_write(AT91_AIC5_DCR, 0);
+
+       /* Disable and clear all interrupts initially */
+       for (i = 0; i < n_irqs; i++) {
+               at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK);
+               at91_aic_write(AT91_AIC5_IDCR, 1);
+               at91_aic_write(AT91_AIC5_ICCR, 1);
+       }
+}
+
 #if defined(CONFIG_OF)
+static unsigned int *at91_aic_irq_priorities;
+
 static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
                                                        irq_hw_number_t hw)
 {
        /* Put virq number in Source Vector Register */
        at91_aic_write(AT91_AIC_SVR(hw), virq);
 
-       /* Active Low interrupt, without priority */
-       at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+       /* Active Low interrupt, with priority */
+       at91_aic_write(AT91_AIC_SMR(hw),
+                      AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
 
-       irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
+       irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
        set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
 
        return 0;
 }
 
+static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq,
+               irq_hw_number_t hw)
+{
+       at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK);
+
+       /* Put virq number in Source Vector Register */
+       at91_aic_write(AT91_AIC5_SVR, virq);
+
+       /* Active Low interrupt, with priority */
+       at91_aic_write(AT91_AIC5_SMR,
+                      AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
+
+       irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
+       set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+       return 0;
+}
+
+static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+                               const u32 *intspec, unsigned int intsize,
+                               irq_hw_number_t *out_hwirq, unsigned int *out_type)
+{
+       if (WARN_ON(intsize < 3))
+               return -EINVAL;
+       if (WARN_ON(intspec[0] >= n_irqs))
+               return -EINVAL;
+       if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
+                   || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
+               return -EINVAL;
+
+       *out_hwirq = intspec[0];
+       *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+       at91_aic_irq_priorities[*out_hwirq] = intspec[2];
+
+       return 0;
+}
+
 static struct irq_domain_ops at91_aic_irq_ops = {
        .map    = at91_aic_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
+       .xlate  = at91_aic_irq_domain_xlate,
 };
 
-int __init at91_aic_of_init(struct device_node *node,
-                                    struct device_node *parent)
+int __init at91_aic_of_common_init(struct device_node *node,
+                                   struct device_node *parent)
 {
+       struct property *prop;
+       const __be32 *p;
+       u32 val;
+
+       at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
+                                 * sizeof(*at91_extern_irq), GFP_KERNEL);
+       if (!at91_extern_irq)
+               return -ENOMEM;
+
+       if (at91_aic_pm_init()) {
+               kfree(at91_extern_irq);
+               return -ENOMEM;
+       }
+
+       at91_aic_irq_priorities = kzalloc(n_irqs
+                                         * sizeof(*at91_aic_irq_priorities),
+                                         GFP_KERNEL);
+       if (!at91_aic_irq_priorities)
+               return -ENOMEM;
+
        at91_aic_base = of_iomap(node, 0);
        at91_aic_np = node;
 
-       at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
+       at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs,
                                                &at91_aic_irq_ops, NULL);
        if (!at91_aic_domain)
                panic("Unable to add AIC irq domain (DT)\n");
 
+       of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
+               if (val >= n_irqs)
+                       pr_warn("AIC: external irq %d >= %d skip it\n",
+                               val, n_irqs);
+               else
+                       set_bit(val, at91_extern_irq);
+       }
+
        irq_set_default_host(at91_aic_domain);
 
-       at91_aic_hw_init(NR_AIC_IRQS);
+       return 0;
+}
+
+int __init at91_aic_of_init(struct device_node *node,
+                                    struct device_node *parent)
+{
+       int err;
+
+       err = at91_aic_of_common_init(node, parent);
+       if (err)
+               return err;
+
+       at91_aic_hw_init(n_irqs);
+
+       return 0;
+}
+
+int __init at91_aic5_of_init(struct device_node *node,
+                                    struct device_node *parent)
+{
+       int err;
+
+       at91_aic_caps |= AT91_AIC_CAP_AIC5;
+       n_irqs = NR_AIC5_IRQS;
+       at91_aic_chip.irq_ack           = at91_aic5_mask_irq;
+       at91_aic_chip.irq_mask          = at91_aic5_mask_irq;
+       at91_aic_chip.irq_unmask        = at91_aic5_unmask_irq;
+       at91_aic_chip.irq_eoi           = at91_aic5_eoi;
+       at91_aic_irq_ops.map            = at91_aic5_irq_map;
+
+       err = at91_aic_of_common_init(node, parent);
+       if (err)
+               return err;
+
+       at91_aic5_hw_init(n_irqs);
 
        return 0;
 }
@@ -204,22 +502,25 @@ int __init at91_aic_of_init(struct device_node *node,
 /*
  * Initialize the AIC interrupt controller.
  */
-void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+void __init at91_aic_init(unsigned int *priority)
 {
        unsigned int i;
        int irq_base;
 
+       if (at91_aic_pm_init())
+               panic("Unable to allocate bit maps\n");
+
        at91_aic_base = ioremap(AT91_AIC, 512);
        if (!at91_aic_base)
                panic("Unable to ioremap AIC registers\n");
 
        /* Add irq domain for AIC */
-       irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
+       irq_base = irq_alloc_descs(-1, 0, n_irqs, 0);
        if (irq_base < 0) {
                WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
                irq_base = 0;
        }
-       at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
+       at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs,
                                                irq_base, 0,
                                                &irq_domain_simple_ops, NULL);
 
@@ -232,15 +533,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
         * The IVR is used by macro get_irqnr_and_base to read and verify.
         * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
         */
-       for (i = 0; i < NR_AIC_IRQS; i++) {
+       for (i = 0; i < n_irqs; i++) {
                /* Put hardware irq number in Source Vector Register: */
-               at91_aic_write(AT91_AIC_SVR(i), i);
+               at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
                /* Active Low interrupt, with the specified priority */
                at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
-
-               irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
+               irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
        }
 
-       at91_aic_hw_init(NR_AIC_IRQS);
+       at91_aic_hw_init(n_irqs);
 }
index 1bfaad628731b262c474bc23217a30f4119eece3..2c2d86505a541fe1964f3f717d7e81c04f9e6a30 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
 
+#include <mach/at91_aic.h>
 #include <mach/at91_pmc.h>
 #include <mach/cpu.h>
 
index c965fd8eb31a14de7478eaaea8a395ab3816bbc8..f15293bd797437805dd7fcf20a6ac062512144ec 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/sched.h>
-#include <linux/timex.h>
 
 #include <asm/sizes.h>
 #include <mach/hardware.h>
@@ -188,7 +187,6 @@ static struct irqaction clps711x_timer_irq = {
 
 static void __init clps711x_timer_init(void)
 {
-       struct timespec tv;
        unsigned int syscon;
 
        syscon = clps_readl(SYSCON1);
@@ -198,10 +196,6 @@ static void __init clps711x_timer_init(void)
        clps_writel(LATCH-1, TC2D); /* 512kHz / 100Hz - 1 */
 
        setup_irq(IRQ_TC2OI, &clps711x_timer_irq);
-
-       tv.tv_nsec = 0;
-       tv.tv_sec = clps_readl(RTCDR);
-       do_settimeofday(&tv);
 }
 
 struct sys_timer clps711x_timer = {
index 3a032a67725c0d0179ddf84102c9d7ebbcbb7127..fc0e028d9405c53cfc9d20e9a726dae59bbe90b6 100644 (file)
  */
 #define PLAT_PHYS_OFFSET       UL(0xc0000000)
 
-#if !defined(CONFIG_ARCH_CDB89712) && !defined (CONFIG_ARCH_AUTCPU12)
-
-#define __virt_to_bus(x)       ((x) - PAGE_OFFSET)
-#define __bus_to_virt(x)       ((x) + PAGE_OFFSET)
-#define __pfn_to_bus(x)                (__pfn_to_phys(x) - PHYS_OFFSET)
-#define __bus_to_pfn(x)                __phys_to_pfn((x) + PHYS_OFFSET)
-
-#endif
-
-
-/*
- * Like the SA1100, the EDB7211 has a large gap between physical RAM
- * banks.  In 2.2, the Psion (CL-PS7110) port added custom support for
- * discontiguous physical memory.  In 2.4, we can use the standard
- * Linux NUMA support.
- *
- * This is not necessary for EP7211 implementations with only one used
- * memory bank.  For those systems, simply undefine CONFIG_DISCONTIGMEM.
- */
-
 /*
  * The PS7211 allows up to 256MB max per DRAM bank, but the EDB7211
  * uses only one of the two banks (bank #1).  However, even within
  * them, so we use 24 for the node max shift to get 16MB node sizes.
  */
 
-/*
- * Because of the wide memory address space between physical RAM banks on the 
- * SA1100, it's much more convenient to use Linux's NUMA support to implement
- * our memory map representation.  Assuming all memory nodes have equal access 
- * characteristics, we then have generic discontiguous memory support.
- *
- * Of course, all this isn't mandatory for SA1100 implementations with only
- * one used memory bank.  For those, simply undefine CONFIG_DISCONTIGMEM.
- *
- * The nodes are matched with the physical memory bank addresses which are 
- * incidentally the same as virtual addresses.
- * 
- *     node 0:  0xc0000000 - 0xc7ffffff
- *     node 1:  0xc8000000 - 0xcfffffff
- *     node 2:  0xd0000000 - 0xd7ffffff
- *     node 3:  0xd8000000 - 0xdfffffff
- */
 #define SECTION_SIZE_BITS      24
 #define MAX_PHYSMEM_BITS       32
 
index 42ee8f33eafbaf7421c6db5b5dd0630971fc660b..f266d90b9efc0e8a4cc79b92b8ece9214c31c2e7 100644 (file)
@@ -86,17 +86,7 @@ static void __init p720t_map_io(void)
        iotable_init(p720t_io_desc, ARRAY_SIZE(p720t_io_desc));
 }
 
-MACHINE_START(P720T, "ARM-Prospector720T")
-       /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .atag_offset    = 0x100,
-       .fixup          = fixup_p720t,
-       .map_io         = p720t_map_io,
-       .init_irq       = clps711x_init_irq,
-       .timer          = &clps711x_timer,
-       .restart        = clps711x_restart,
-MACHINE_END
-
-static int p720t_hw_init(void)
+static void __init p720t_init_early(void)
 {
        /*
         * Power down as much as possible in case we don't
@@ -111,13 +101,19 @@ static int p720t_hw_init(void)
        PLD_CODEC = 0;
        PLD_TCH   = 0;
        PLD_SPI   = 0;
-#ifndef CONFIG_DEBUG_LL
-       PLD_COM2  = 0;
-       PLD_COM1  = 0;
-#endif
-
-       return 0;
+       if (!IS_ENABLED(CONFIG_DEBUG_LL)) {
+               PLD_COM2 = 0;
+               PLD_COM1 = 0;
+       }
 }
 
-__initcall(p720t_hw_init);
-
+MACHINE_START(P720T, "ARM-Prospector720T")
+       /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+       .atag_offset    = 0x100,
+       .fixup          = fixup_p720t,
+       .init_early     = p720t_init_early,
+       .map_io         = p720t_map_io,
+       .init_irq       = clps711x_init_irq,
+       .timer          = &clps711x_timer,
+       .restart        = clps711x_restart,
+MACHINE_END
index 32d837d8eab97ded50f9d861faee3b16f3fb0dd0..2ce1ef07c13d63c52edea705c655ea2f8ef3469f 100644 (file)
@@ -4,6 +4,7 @@ config AINTC
        bool
 
 config CP_INTC
+       select IRQ_DOMAIN
        bool
 
 config ARCH_DAVINCI_DMx
index 2db78bd5c835dbda436faf7184fc837b8eed8f0e..2227effcb0e98bdea4968b95617e06cf3c0b5f39 100644 (file)
@@ -39,3 +39,4 @@ obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD) += board-omapl138-hawk.o
 obj-$(CONFIG_CPU_FREQ)                 += cpufreq.o
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
 obj-$(CONFIG_SUSPEND)                  += pm.o sleep.o
+obj-$(CONFIG_HAVE_CLK)                 += pm_domain.o
index f83152d643c5d58921a7b91a826a1790b7bbe4f9..006dae8dfe443b3474ae6df73b5c97cf93502f33 100644 (file)
@@ -9,9 +9,14 @@
  * kind, whether express or implied.
  */
 
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <mach/common.h>
 #include <mach/cp_intc.h>
@@ -28,7 +33,7 @@ static inline void cp_intc_write(unsigned long value, unsigned offset)
 
 static void cp_intc_ack_irq(struct irq_data *d)
 {
-       cp_intc_write(d->irq, CP_INTC_SYS_STAT_IDX_CLR);
+       cp_intc_write(d->hwirq, CP_INTC_SYS_STAT_IDX_CLR);
 }
 
 /* Disable interrupt */
@@ -36,20 +41,20 @@ static void cp_intc_mask_irq(struct irq_data *d)
 {
        /* XXX don't know why we need to disable nIRQ here... */
        cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR);
-       cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_CLR);
+       cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_CLR);
        cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
 }
 
 /* Enable interrupt */
 static void cp_intc_unmask_irq(struct irq_data *d)
 {
-       cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_SET);
+       cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_SET);
 }
 
 static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type)
 {
-       unsigned reg            = BIT_WORD(d->irq);
-       unsigned mask           = BIT_MASK(d->irq);
+       unsigned reg            = BIT_WORD(d->hwirq);
+       unsigned mask           = BIT_MASK(d->hwirq);
        unsigned polarity       = cp_intc_read(CP_INTC_SYS_POLARITY(reg));
        unsigned type           = cp_intc_read(CP_INTC_SYS_TYPE(reg));
 
@@ -99,18 +104,43 @@ static struct irq_chip cp_intc_irq_chip = {
        .irq_set_wake   = cp_intc_set_wake,
 };
 
-void __init cp_intc_init(void)
+static struct irq_domain *cp_intc_domain;
+
+static int cp_intc_host_map(struct irq_domain *h, unsigned int virq,
+                         irq_hw_number_t hw)
 {
-       unsigned long num_irq   = davinci_soc_info.intc_irq_num;
+       pr_debug("cp_intc_host_map(%d, 0x%lx)\n", virq, hw);
+
+       irq_set_chip(virq, &cp_intc_irq_chip);
+       set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+       irq_set_handler(virq, handle_edge_irq);
+       return 0;
+}
+
+static const struct irq_domain_ops cp_intc_host_ops = {
+       .map = cp_intc_host_map,
+       .xlate = irq_domain_xlate_onetwocell,
+};
+
+int __init cp_intc_of_init(struct device_node *node, struct device_node *parent)
+{
+       u32 num_irq             = davinci_soc_info.intc_irq_num;
        u8 *irq_prio            = davinci_soc_info.intc_irq_prios;
        u32 *host_map           = davinci_soc_info.intc_host_map;
        unsigned num_reg        = BITS_TO_LONGS(num_irq);
-       int i;
+       int i, irq_base;
 
        davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC;
-       davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K);
+       if (node) {
+               davinci_intc_base = of_iomap(node, 0);
+               if (of_property_read_u32(node, "ti,intc-size", &num_irq))
+                       pr_warn("unable to get intc-size, default to %d\n",
+                               num_irq);
+       } else {
+               davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K);
+       }
        if (WARN_ON(!davinci_intc_base))
-               return;
+               return -EINVAL;
 
        cp_intc_write(0, CP_INTC_GLOBAL_ENABLE);
 
@@ -165,13 +195,28 @@ void __init cp_intc_init(void)
                for (i = 0; host_map[i] != -1; i++)
                        cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i));
 
-       /* Set up genirq dispatching for cp_intc */
-       for (i = 0; i < num_irq; i++) {
-               irq_set_chip(i, &cp_intc_irq_chip);
-               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-               irq_set_handler(i, handle_edge_irq);
+       irq_base = irq_alloc_descs(-1, 0, num_irq, 0);
+       if (irq_base < 0) {
+               pr_warn("Couldn't allocate IRQ numbers\n");
+               irq_base = 0;
+       }
+
+       /* create a legacy host */
+       cp_intc_domain = irq_domain_add_legacy(node, num_irq,
+                                       irq_base, 0, &cp_intc_host_ops, NULL);
+
+       if (!cp_intc_domain) {
+               pr_err("cp_intc: failed to allocate irq host!\n");
+               return -EINVAL;
        }
 
        /* Enable global interrupt */
        cp_intc_write(1, CP_INTC_GLOBAL_ENABLE);
+
+       return 0;
+}
+
+void __init cp_intc_init(void)
+{
+       cp_intc_of_init(NULL, NULL);
 }
index 4e8190eed673dca87281134821ab5fa06ac477f7..d13d8dfa2b0d6c6d871c80a5ebdbb19f237476b7 100644 (file)
@@ -52,5 +52,6 @@
 #define CP_INTC_VECTOR_ADDR(n)         (0x2000 + (n << 2))
 
 void __init cp_intc_init(void);
+int __init cp_intc_of_init(struct device_node *, struct device_node *);
 
 #endif /* __ASM_HARDWARE_CP_INTC_H */
diff --git a/arch/arm/mach-davinci/include/mach/dm365.h b/arch/arm/mach-davinci/include/mach/dm365.h
deleted file mode 100644 (file)
index b9bf3d6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* empty, remove once unused */
diff --git a/arch/arm/mach-davinci/include/mach/dm646x.h b/arch/arm/mach-davinci/include/mach/dm646x.h
deleted file mode 100644 (file)
index b9bf3d6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* empty, remove once unused */
index 768b3c0602140e789286b7182bb07e2b31336282..cf5f573eb5fd713c6d407bb752a870e7abbc0992 100644 (file)
 #endif
 #if defined(CONFIG_CP_INTC)
 1001:          ldr \irqnr, [\base, #0x80] /* get irq number */
+               mov \tmp, \irqnr, lsr #31
                and \irqnr, \irqnr, #0xff  /* irq is in bits 0-9 */
-               mov \tmp, \irqnr, lsr #3
-               and \tmp, \tmp, #0xfc
-               add \tmp, \tmp, #0x280 /* get the register offset */
-               ldr \irqstat, [\base, \tmp] /* get the intc status */
-               cmp \irqstat, #0x0
+               and \tmp, \tmp, #0x1
+               cmp \tmp, #0x1
 #endif
 1002:
                .endm
diff --git a/arch/arm/mach-davinci/pm_domain.c b/arch/arm/mach-davinci/pm_domain.c
new file mode 100644 (file)
index 0000000..00946e2
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Runtime PM support code for DaVinci
+ *
+ * Author: Kevin Hilman
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/init.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
+#include <linux/platform_device.h>
+
+#ifdef CONFIG_PM_RUNTIME
+static int davinci_pm_runtime_suspend(struct device *dev)
+{
+       int ret;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       ret = pm_generic_runtime_suspend(dev);
+       if (ret)
+               return ret;
+
+       ret = pm_clk_suspend(dev);
+       if (ret) {
+               pm_generic_runtime_resume(dev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int davinci_pm_runtime_resume(struct device *dev)
+{
+       dev_dbg(dev, "%s\n", __func__);
+
+       pm_clk_resume(dev);
+       return pm_generic_runtime_resume(dev);
+}
+#endif
+
+static struct dev_pm_domain davinci_pm_domain = {
+       .ops = {
+               SET_RUNTIME_PM_OPS(davinci_pm_runtime_suspend,
+                                  davinci_pm_runtime_resume, NULL)
+               USE_PLATFORM_PM_SLEEP_OPS
+       },
+};
+
+static struct pm_clk_notifier_block platform_bus_notifier = {
+       .pm_domain = &davinci_pm_domain,
+};
+
+static int __init davinci_pm_runtime_init(void)
+{
+       pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
+
+       return 0;
+}
+core_initcall(davinci_pm_runtime_init);
index 226949dc4ac04a242c40e215d23818421342b99c..f953bb54aa9d31d590791d97aaaf770aaaecfd93 100644 (file)
@@ -50,5 +50,6 @@
 #define POWER_MANAGEMENT       (BRIDGE_VIRT_BASE | 0x011c)
 
 #define TIMER_VIRT_BASE                (BRIDGE_VIRT_BASE | 0x0300)
+#define TIMER_PHYS_BASE         (BRIDGE_PHYS_BASE | 0x0300)
 
 #endif
index ad1165d488c13f393bf352a00f0e03b62265f3cc..d52b0ef313b7e53c2efa6de67d0ddeddc4790ca5 100644 (file)
@@ -78,6 +78,7 @@
 
 /* North-South Bridge */
 #define BRIDGE_VIRT_BASE       (DOVE_SB_REGS_VIRT_BASE | 0x20000)
+#define BRIDGE_PHYS_BASE       (DOVE_SB_REGS_PHYS_BASE | 0x20000)
 
 /* Cryptographic Engine */
 #define DOVE_CRYPT_PHYS_BASE   (DOVE_SB_REGS_PHYS_BASE | 0x30000)
index 4dd07a0e3604a19498cf4fa507b544a666e2d8a5..4afe52aaaff3573e97e6d46ba479b56303445f89 100644 (file)
@@ -797,6 +797,102 @@ static struct platform_device ep93xx_wdt_device = {
        .resource       = ep93xx_wdt_resources,
 };
 
+/*************************************************************************
+ * EP93xx IDE
+ *************************************************************************/
+static struct resource ep93xx_ide_resources[] = {
+       DEFINE_RES_MEM(EP93XX_IDE_PHYS_BASE, 0x38),
+       DEFINE_RES_IRQ(IRQ_EP93XX_EXT3),
+};
+
+static struct platform_device ep93xx_ide_device = {
+       .name           = "ep93xx-ide",
+       .id             = -1,
+       .dev            = {
+               .dma_mask               = &ep93xx_ide_device.dev.coherent_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+       .num_resources  = ARRAY_SIZE(ep93xx_ide_resources),
+       .resource       = ep93xx_ide_resources,
+};
+
+void __init ep93xx_register_ide(void)
+{
+       platform_device_register(&ep93xx_ide_device);
+}
+
+int ep93xx_ide_acquire_gpio(struct platform_device *pdev)
+{
+       int err;
+       int i;
+
+       err = gpio_request(EP93XX_GPIO_LINE_EGPIO2, dev_name(&pdev->dev));
+       if (err)
+               return err;
+       err = gpio_request(EP93XX_GPIO_LINE_EGPIO15, dev_name(&pdev->dev));
+       if (err)
+               goto fail_egpio15;
+       for (i = 2; i < 8; i++) {
+               err = gpio_request(EP93XX_GPIO_LINE_E(i), dev_name(&pdev->dev));
+               if (err)
+                       goto fail_gpio_e;
+       }
+       for (i = 4; i < 8; i++) {
+               err = gpio_request(EP93XX_GPIO_LINE_G(i), dev_name(&pdev->dev));
+               if (err)
+                       goto fail_gpio_g;
+       }
+       for (i = 0; i < 8; i++) {
+               err = gpio_request(EP93XX_GPIO_LINE_H(i), dev_name(&pdev->dev));
+               if (err)
+                       goto fail_gpio_h;
+       }
+
+       /* GPIO ports E[7:2], G[7:4] and H used by IDE */
+       ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_EONIDE |
+                                EP93XX_SYSCON_DEVCFG_GONIDE |
+                                EP93XX_SYSCON_DEVCFG_HONIDE);
+       return 0;
+
+fail_gpio_h:
+       for (--i; i >= 0; --i)
+               gpio_free(EP93XX_GPIO_LINE_H(i));
+       i = 8;
+fail_gpio_g:
+       for (--i; i >= 4; --i)
+               gpio_free(EP93XX_GPIO_LINE_G(i));
+       i = 8;
+fail_gpio_e:
+       for (--i; i >= 2; --i)
+               gpio_free(EP93XX_GPIO_LINE_E(i));
+       gpio_free(EP93XX_GPIO_LINE_EGPIO15);
+fail_egpio15:
+       gpio_free(EP93XX_GPIO_LINE_EGPIO2);
+       return err;
+}
+EXPORT_SYMBOL(ep93xx_ide_acquire_gpio);
+
+void ep93xx_ide_release_gpio(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 2; i < 8; i++)
+               gpio_free(EP93XX_GPIO_LINE_E(i));
+       for (i = 4; i < 8; i++)
+               gpio_free(EP93XX_GPIO_LINE_G(i));
+       for (i = 0; i < 8; i++)
+               gpio_free(EP93XX_GPIO_LINE_H(i));
+       gpio_free(EP93XX_GPIO_LINE_EGPIO15);
+       gpio_free(EP93XX_GPIO_LINE_EGPIO2);
+
+
+       /* GPIO ports E[7:2], G[7:4] and H used by GPIO */
+       ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_EONIDE |
+                              EP93XX_SYSCON_DEVCFG_GONIDE |
+                              EP93XX_SYSCON_DEVCFG_HONIDE);
+}
+EXPORT_SYMBOL(ep93xx_ide_release_gpio);
+
 void __init ep93xx_init_devices(void)
 {
        /* Disallow access to MaverickCrunch initially */
index d74c5cddb98b654972ae986489f90c0e700aa190..337ab7cf4c16fc81391883c435e2be66d1f44298 100644 (file)
@@ -91,8 +91,8 @@ static void __init edb93xx_register_i2c(void)
                ep93xx_register_i2c(&edb93xx_i2c_gpio_data,
                                    edb93xxa_i2c_board_info,
                                    ARRAY_SIZE(edb93xxa_i2c_board_info));
-       } else if (machine_is_edb9307() || machine_is_edb9312() ||
-                  machine_is_edb9315()) {
+       } else if (machine_is_edb9302() || machine_is_edb9307()
+               || machine_is_edb9312() || machine_is_edb9315()) {
                ep93xx_register_i2c(&edb93xx_i2c_gpio_data,
                                    edb93xx_i2c_board_info,
                                    ARRAY_SIZE(edb93xx_i2c_board_info));
@@ -233,6 +233,29 @@ static void __init edb93xx_register_fb(void)
 }
 
 
+/*************************************************************************
+ * EDB93xx IDE
+ *************************************************************************/
+static int __init edb93xx_has_ide(void)
+{
+       /*
+        * Although EDB9312 and EDB9315 do have IDE capability, they have
+        * INTRQ line wired as pull-up, which makes using IDE interface
+        * problematic.
+        */
+       return machine_is_edb9312() || machine_is_edb9315() ||
+              machine_is_edb9315a();
+}
+
+static void __init edb93xx_register_ide(void)
+{
+       if (!edb93xx_has_ide())
+               return;
+
+       ep93xx_register_ide();
+}
+
+
 static void __init edb93xx_init_machine(void)
 {
        ep93xx_init_devices();
@@ -243,6 +266,7 @@ static void __init edb93xx_init_machine(void)
        edb93xx_register_i2s();
        edb93xx_register_pwm();
        edb93xx_register_fb();
+       edb93xx_register_ide();
 }
 
 
index 1ecb040d98bf7f3e390f76473ec85c7c50e377a3..33a5122c6dc8bac0954655a5d5795b12a0d0df85 100644 (file)
@@ -48,6 +48,9 @@ void ep93xx_register_i2s(void);
 int ep93xx_i2s_acquire(void);
 void ep93xx_i2s_release(void);
 void ep93xx_register_ac97(void);
+void ep93xx_register_ide(void);
+int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
+void ep93xx_ide_release_gpio(struct platform_device *pdev);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
index 979fba72292628e8bddd22ba7660df9514bb2ebb..7bf7ff8beae73f28aec97693a9cda48c6a8212bf 100644 (file)
@@ -69,6 +69,7 @@
 
 #define EP93XX_BOOT_ROM_BASE           EP93XX_AHB_IOMEM(0x00090000)
 
+#define EP93XX_IDE_PHYS_BASE           EP93XX_AHB_PHYS(0x000a0000)
 #define EP93XX_IDE_BASE                        EP93XX_AHB_IOMEM(0x000a0000)
 
 #define EP93XX_VIC1_BASE               EP93XX_AHB_IOMEM(0x000b0000)
index bcb7db45314599cd975a6ad904d199c881c4e6cf..26fe9de35ecb8ca715f73a4cee3955591b1e2b2a 100644 (file)
@@ -586,17 +586,17 @@ static struct clk exynos4_init_clocks_off[] = {
                .ctrlbit        = (1 << 13),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "exynos4210-spi.0",
                .enable         = exynos4_clk_ip_peril_ctrl,
                .ctrlbit        = (1 << 16),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "exynos4210-spi.1",
                .enable         = exynos4_clk_ip_peril_ctrl,
                .ctrlbit        = (1 << 17),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.2",
+               .devname        = "exynos4210-spi.2",
                .enable         = exynos4_clk_ip_peril_ctrl,
                .ctrlbit        = (1 << 18),
        }, {
@@ -1242,40 +1242,67 @@ static struct clksrc_clk exynos4_clk_sclk_mmc3 = {
        .reg_div = { .reg = EXYNOS4_CLKDIV_FSYS2, .shift = 24, .size = 8 },
 };
 
+static struct clksrc_clk exynos4_clk_mdout_spi0 = {
+       .clk    = {
+               .name           = "mdout_spi",
+               .devname        = "exynos4210-spi.0",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 16, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_mdout_spi1 = {
+       .clk    = {
+               .name           = "mdout_spi",
+               .devname        = "exynos4210-spi.1",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 20, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos4_clk_mdout_spi2 = {
+       .clk    = {
+               .name           = "mdout_spi",
+               .devname        = "exynos4210-spi.2",
+       },
+       .sources = &exynos4_clkset_group,
+       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 24, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL2, .shift = 0, .size = 4 },
+};
+
 static struct clksrc_clk exynos4_clk_sclk_spi0 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "exynos4210-spi.0",
+               .parent         = &exynos4_clk_mdout_spi0.clk,
                .enable         = exynos4_clksrc_mask_peril1_ctrl,
                .ctrlbit        = (1 << 16),
        },
-       .sources = &exynos4_clkset_group,
-       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 16, .size = 4 },
-       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 0, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 8, .size = 8 },
 };
 
 static struct clksrc_clk exynos4_clk_sclk_spi1 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "exynos4210-spi.1",
+               .parent         = &exynos4_clk_mdout_spi1.clk,
                .enable         = exynos4_clksrc_mask_peril1_ctrl,
                .ctrlbit        = (1 << 20),
        },
-       .sources = &exynos4_clkset_group,
-       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 20, .size = 4 },
-       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 16, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL1, .shift = 24, .size = 8 },
 };
 
 static struct clksrc_clk exynos4_clk_sclk_spi2 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.2",
+               .devname        = "exynos4210-spi.2",
+               .parent         = &exynos4_clk_mdout_spi2.clk,
                .enable         = exynos4_clksrc_mask_peril1_ctrl,
                .ctrlbit        = (1 << 24),
        },
-       .sources = &exynos4_clkset_group,
-       .reg_src = { .reg = EXYNOS4_CLKSRC_PERIL1, .shift = 24, .size = 4 },
-       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL2, .shift = 0, .size = 4 },
+       .reg_div = { .reg = EXYNOS4_CLKDIV_PERIL2, .shift = 8, .size = 8 },
 };
 
 /* Clock initialization code */
@@ -1331,7 +1358,9 @@ static struct clksrc_clk *exynos4_clksrc_cdev[] = {
        &exynos4_clk_sclk_spi0,
        &exynos4_clk_sclk_spi1,
        &exynos4_clk_sclk_spi2,
-
+       &exynos4_clk_mdout_spi0,
+       &exynos4_clk_mdout_spi1,
+       &exynos4_clk_mdout_spi2,
 };
 
 static struct clk_lookup exynos4_clk_lookup[] = {
@@ -1347,9 +1376,9 @@ static struct clk_lookup exynos4_clk_lookup[] = {
        CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos4_clk_pdma0),
        CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos4_clk_pdma1),
        CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos4_clk_mdma1),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &exynos4_clk_sclk_spi0.clk),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk0", &exynos4_clk_sclk_spi1.clk),
-       CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk0", &exynos4_clk_sclk_spi2.clk),
+       CLKDEV_INIT("exynos4210-spi.0", "spi_busclk0", &exynos4_clk_sclk_spi0.clk),
+       CLKDEV_INIT("exynos4210-spi.1", "spi_busclk0", &exynos4_clk_sclk_spi1.clk),
+       CLKDEV_INIT("exynos4210-spi.2", "spi_busclk0", &exynos4_clk_sclk_spi2.clk),
 };
 
 static int xtal_rate;
index fefa336be2b4baf8d841a809766be3bdf9338f83..774533c670667c1a7a8e16986e7ababa841ee48e 100644 (file)
@@ -131,6 +131,11 @@ static int exynos5_clksrc_mask_peric0_ctrl(struct clk *clk, int enable)
        return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable);
 }
 
+static int exynos5_clksrc_mask_peric1_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC1, clk, enable);
+}
+
 static int exynos5_clk_ip_acp_ctrl(struct clk *clk, int enable)
 {
        return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ACP, clk, enable);
@@ -740,6 +745,24 @@ static struct clk exynos5_init_clocks_off[] = {
                .parent         = &exynos5_clk_aclk_66.clk,
                .enable         = exynos5_clk_ip_peric_ctrl,
                .ctrlbit        = (1 << 14),
+       }, {
+               .name           = "spi",
+               .devname        = "exynos4210-spi.0",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 16),
+       }, {
+               .name           = "spi",
+               .devname        = "exynos4210-spi.1",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 17),
+       }, {
+               .name           = "spi",
+               .devname        = "exynos4210-spi.2",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peric_ctrl,
+               .ctrlbit        = (1 << 18),
        }, {
                .name           = SYSMMU_CLOCK_NAME,
                .devname        = SYSMMU_CLOCK_DEVNAME(mfc_l, 0),
@@ -1034,6 +1057,69 @@ static struct clksrc_clk exynos5_clk_sclk_mmc3 = {
        .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 24, .size = 8 },
 };
 
+static struct clksrc_clk exynos5_clk_mdout_spi0 = {
+       .clk    = {
+               .name           = "mdout_spi",
+               .devname        = "exynos4210-spi.0",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 16, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_mdout_spi1 = {
+       .clk    = {
+               .name           = "mdout_spi",
+               .devname        = "exynos4210-spi.1",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 20, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_mdout_spi2 = {
+       .clk    = {
+               .name           = "mdout_spi",
+               .devname        = "exynos4210-spi.2",
+       },
+       .sources = &exynos5_clkset_group,
+       .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 24, .size = 4 },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC2, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_spi0 = {
+       .clk    = {
+               .name           = "sclk_spi",
+               .devname        = "exynos4210-spi.0",
+               .parent         = &exynos5_clk_mdout_spi0.clk,
+               .enable         = exynos5_clksrc_mask_peric1_ctrl,
+               .ctrlbit        = (1 << 16),
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_spi1 = {
+       .clk    = {
+               .name           = "sclk_spi",
+               .devname        = "exynos4210-spi.1",
+               .parent         = &exynos5_clk_mdout_spi1.clk,
+               .enable         = exynos5_clksrc_mask_peric1_ctrl,
+               .ctrlbit        = (1 << 20),
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_spi2 = {
+       .clk    = {
+               .name           = "sclk_spi",
+               .devname        = "exynos4210-spi.2",
+               .parent         = &exynos5_clk_mdout_spi2.clk,
+               .enable         = exynos5_clksrc_mask_peric1_ctrl,
+               .ctrlbit        = (1 << 24),
+       },
+       .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC2, .shift = 8, .size = 8 },
+};
+
 static struct clksrc_clk exynos5_clksrcs[] = {
        {
                .clk    = {
@@ -1148,6 +1234,12 @@ static struct clksrc_clk *exynos5_sysclks[] = {
        &exynos5_clk_dout_mmc4,
        &exynos5_clk_aclk_acp,
        &exynos5_clk_pclk_acp,
+       &exynos5_clk_sclk_spi0,
+       &exynos5_clk_sclk_spi1,
+       &exynos5_clk_sclk_spi2,
+       &exynos5_clk_mdout_spi0,
+       &exynos5_clk_mdout_spi1,
+       &exynos5_clk_mdout_spi2,
 };
 
 static struct clk *exynos5_clk_cdev[] = {
@@ -1176,6 +1268,9 @@ static struct clk_lookup exynos5_clk_lookup[] = {
        CLKDEV_INIT("exynos4-sdhci.1", "mmc_busclk.2", &exynos5_clk_sclk_mmc1.clk),
        CLKDEV_INIT("exynos4-sdhci.2", "mmc_busclk.2", &exynos5_clk_sclk_mmc2.clk),
        CLKDEV_INIT("exynos4-sdhci.3", "mmc_busclk.2", &exynos5_clk_sclk_mmc3.clk),
+       CLKDEV_INIT("exynos4210-spi.0", "spi_busclk0", &exynos5_clk_sclk_spi0.clk),
+       CLKDEV_INIT("exynos4210-spi.1", "spi_busclk0", &exynos5_clk_sclk_spi1.clk),
+       CLKDEV_INIT("exynos4210-spi.2", "spi_busclk0", &exynos5_clk_sclk_spi2.clk),
        CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos5_clk_pdma0),
        CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos5_clk_pdma1),
        CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos5_clk_mdma1),
index 742edd3bbec34b14f9c6e1817029b9c81f602c03..4eb39cdf75eab7b524ab090af5179315797107ce 100644 (file)
@@ -540,7 +540,8 @@ static struct irq_domain_ops combiner_irq_domain_ops = {
        .map    = combiner_irq_domain_map,
 };
 
-void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
+static void __init combiner_init(void __iomem *combiner_base,
+                                struct device_node *np)
 {
        int i, irq, irq_base;
        unsigned int max_nr, nr_irq;
@@ -712,31 +713,6 @@ static int __init exynos4_l2x0_cache_init(void)
 early_initcall(exynos4_l2x0_cache_init);
 #endif
 
-static int __init exynos5_l2_cache_init(void)
-{
-       unsigned int val;
-
-       if (!soc_is_exynos5250())
-               return 0;
-
-       asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
-                    "bic %0, %0, #(1 << 2)\n"  /* cache disable */
-                    "mcr p15, 0, %0, c1, c0, 0\n"
-                    "mrc p15, 1, %0, c9, c0, 2\n"
-                    : "=r"(val));
-
-       val |= (1 << 9) | (1 << 5) | (2 << 6) | (2 << 0);
-
-       asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val));
-       asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
-                    "orr %0, %0, #(1 << 2)\n"  /* cache enable */
-                    "mcr p15, 0, %0, c1, c0, 0\n"
-                    : : "r"(val));
-
-       return 0;
-}
-early_initcall(exynos5_l2_cache_init);
-
 static int __init exynos_init(void)
 {
        printk(KERN_INFO "EXYNOS: Initializing architecture\n");
index 7a4b4789eb7288205fcfcd555dcf50ffdb962753..35bced6f9092141920152664267362a54cdf8161 100644 (file)
 #define IRQ_IIC6                       EXYNOS4_IRQ_IIC6
 #define IRQ_IIC7                       EXYNOS4_IRQ_IIC7
 
+#define IRQ_SPI0                       EXYNOS4_IRQ_SPI0
+#define IRQ_SPI1                       EXYNOS4_IRQ_SPI1
+#define IRQ_SPI2                       EXYNOS4_IRQ_SPI2
+
 #define IRQ_USB_HOST                   EXYNOS4_IRQ_USB_HOST
 #define IRQ_OTG                                EXYNOS4_IRQ_USB_HSOTG
 
index ca4aa89aa46b357fe5ff04710bd9ffdf4caf361b..c72b675b3e4b98f07dd26353d1dcbb3ee7ae12e6 100644 (file)
 #define EXYNOS4_PA_SPI0                        0x13920000
 #define EXYNOS4_PA_SPI1                        0x13930000
 #define EXYNOS4_PA_SPI2                        0x13940000
+#define EXYNOS5_PA_SPI0                        0x12D20000
+#define EXYNOS5_PA_SPI1                        0x12D30000
+#define EXYNOS5_PA_SPI2                        0x12D40000
 
 #define EXYNOS4_PA_GPIO1               0x11400000
 #define EXYNOS4_PA_GPIO2               0x11000000
index 43a99e6f56ab68e638621f8fb9e6b23c910005b3..d4e392b811a315d6a477f677b4462359ed9c8f6f 100644 (file)
 
 #define EXYNOS5_USB_CFG                                                S5P_PMUREG(0x0230)
 
+#define EXYNOS5_AUTO_WDTRESET_DISABLE                          S5P_PMUREG(0x0408)
+#define EXYNOS5_MASK_WDTRESET_REQUEST                          S5P_PMUREG(0x040C)
+
+#define EXYNOS5_SYS_WDTRESET                                   (1 << 20)
+
 #define EXYNOS5_ARM_CORE0_SYS_PWR_REG                          S5P_PMUREG(0x1000)
 #define EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG            S5P_PMUREG(0x1004)
 #define EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG          S5P_PMUREG(0x1008)
index c337cf3a71bf35e39bf4780f481a36a1c54db9aa..07277735252e39b3437e8cdb2fddeaf44e1c3cd9 100644 (file)
 #define PHY1_COMMON_ON_N               (1 << 7)
 #define PHY0_COMMON_ON_N               (1 << 4)
 #define PHY0_ID_PULLUP                 (1 << 2)
-#define CLKSEL_MASK                    (0x3 << 0)
-#define CLKSEL_SHIFT                   (0)
-#define CLKSEL_48M                     (0x0 << 0)
-#define CLKSEL_12M                     (0x2 << 0)
-#define CLKSEL_24M                     (0x3 << 0)
+
+#define EXYNOS4_CLKSEL_SHIFT           (0)
+
+#define EXYNOS4210_CLKSEL_MASK         (0x3 << 0)
+#define EXYNOS4210_CLKSEL_48M          (0x0 << 0)
+#define EXYNOS4210_CLKSEL_12M          (0x2 << 0)
+#define EXYNOS4210_CLKSEL_24M          (0x3 << 0)
+
+#define EXYNOS4X12_CLKSEL_MASK         (0x7 << 0)
+#define EXYNOS4X12_CLKSEL_9600K                (0x0 << 0)
+#define EXYNOS4X12_CLKSEL_10M          (0x1 << 0)
+#define EXYNOS4X12_CLKSEL_12M          (0x2 << 0)
+#define EXYNOS4X12_CLKSEL_19200K       (0x3 << 0)
+#define EXYNOS4X12_CLKSEL_20M          (0x4 << 0)
+#define EXYNOS4X12_CLKSEL_24M          (0x5 << 0)
 
 #define EXYNOS4_RSTCON                 EXYNOS4_HSOTG_PHYREG(0x08)
 #define HOST_LINK_PORT_SWRST_MASK      (0xf << 6)
diff --git a/arch/arm/mach-exynos/include/mach/spi-clocks.h b/arch/arm/mach-exynos/include/mach/spi-clocks.h
deleted file mode 100644 (file)
index c71a5fb..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/spi-clocks.h
- *
- * Copyright (C) 2011 Samsung Electronics Co. Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_SPI_CLKS_H
-#define __ASM_ARCH_SPI_CLKS_H __FILE__
-
-/* Must source from SCLK_SPI */
-#define EXYNOS_SPI_SRCCLK_SCLK         0
-
-#endif /* __ASM_ARCH_SPI_CLKS_H */
index e7e9743543acd6384f38f5cfcfcd7b4760872225..b2b5d5faa74854adea983f3b2b1b085b6d133540 100644 (file)
@@ -55,6 +55,12 @@ static const struct of_dev_auxdata exynos4210_auxdata_lookup[] __initconst = {
                                "exynos4-sdhci.3", NULL),
        OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(0),
                                "s3c2440-i2c.0", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI0,
+                               "exynos4210-spi.0", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI1,
+                               "exynos4210-spi.1", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI2,
+                               "exynos4210-spi.2", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA0, "dma-pl330.0", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_PDMA1, "dma-pl330.1", NULL),
        {},
index 7b1e11a228cce49776135f140316c83182f4d440..ef770bc2318fcbd074387a6c5278a007f169773d 100644 (file)
@@ -47,6 +47,12 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
                                "s3c2440-i2c.0", NULL),
        OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(1),
                                "s3c2440-i2c.1", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS5_PA_SPI0,
+                               "exynos4210-spi.0", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS5_PA_SPI1,
+                               "exynos4210-spi.1", NULL),
+       OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS5_PA_SPI2,
+                               "exynos4210-spi.2", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_MDMA1, "dma-pl330.2", NULL),
index 656f8fc9addd3b67ecaafbe9207f279da01b3b70..f3b328d0aff680cf5384e9967a284ddc7eebc070 100644 (file)
@@ -50,7 +50,6 @@
 #include <plat/gpio-cfg.h>
 #include <plat/iic.h>
 #include <plat/mfc.h>
-#include <plat/pd.h>
 #include <plat/fimc-core.h>
 #include <plat/camport.h>
 #include <plat/mipi_csis.h>
index f5572be9d7bf38480f931618d27507738aaf1ad6..873c708fd340854021048fa6fbb3f3672974b92f 100644 (file)
@@ -38,7 +38,6 @@
 #include <plat/clock.h>
 #include <plat/gpio-cfg.h>
 #include <plat/backlight.h>
-#include <plat/pd.h>
 #include <plat/fb.h>
 #include <plat/mfc.h>
 
index 262e9e446a96a62934f58b978c81dcdd98e1c1a3..5fb209c4a594d961dbc0314f881594d43133d222 100644 (file)
@@ -34,7 +34,6 @@
 #include <plat/keypad.h>
 #include <plat/sdhci.h>
 #include <plat/iic.h>
-#include <plat/pd.h>
 #include <plat/gpio-cfg.h>
 #include <plat/backlight.h>
 #include <plat/mfc.h>
index cd92fa86ba41248da1d8de5e8f122edca102d290..68719f57dceab9e9c49bcf21e397eb832f9f3e54 100644 (file)
@@ -39,7 +39,6 @@
 #include <plat/fb.h>
 #include <plat/mfc.h>
 #include <plat/sdhci.h>
-#include <plat/pd.h>
 #include <plat/regs-fb-v4.h>
 #include <plat/fimc-core.h>
 #include <plat/s5p-time.h>
index e9fafcf163de8982287876a7ca6d6cf94488f472..373c3c00d24cdbbe054a1aae60625d97188e6208 100644 (file)
@@ -119,7 +119,9 @@ static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev,
                                                struct exynos_pm_domain *pd)
 {
        if (pdev->dev.bus) {
-               if (pm_genpd_add_device(&pd->pd, &pdev->dev))
+               if (!pm_genpd_add_device(&pd->pd, &pdev->dev))
+                       pm_genpd_dev_need_restore(&pdev->dev, true);
+               else
                        pr_info("%s: error in adding %s device to %s power"
                                "domain\n", __func__, dev_name(&pdev->dev),
                                pd->name);
@@ -151,9 +153,12 @@ static __init int exynos4_pm_init_power_domain(void)
        if (of_have_populated_dt())
                return exynos_pm_dt_parse_domains();
 
-       for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++)
-               pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL,
-                               exynos4_pm_domains[idx]->is_off);
+       for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++) {
+               struct exynos_pm_domain *pd = exynos4_pm_domains[idx];
+               int on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN;
+
+               pm_genpd_init(&pd->pd, NULL, !on);
+       }
 
 #ifdef CONFIG_S5P_DEV_FIMD0
        exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0);
index 4aacb66f71618da5d865a04a868878ef380aebea..3a48c852be6c1a1e97117b96512d6e4e1ca452c5 100644 (file)
@@ -315,7 +315,7 @@ static struct exynos_pmu_conf exynos5250_pmu_config[] = {
        { PMU_TABLE_END,},
 };
 
-void __iomem *exynos5_list_both_cnt_feed[] = {
+static void __iomem *exynos5_list_both_cnt_feed[] = {
        EXYNOS5_ARM_CORE0_OPTION,
        EXYNOS5_ARM_CORE1_OPTION,
        EXYNOS5_ARM_COMMON_OPTION,
@@ -329,7 +329,7 @@ void __iomem *exynos5_list_both_cnt_feed[] = {
        EXYNOS5_TOP_PWR_SYSMEM_OPTION,
 };
 
-void __iomem *exynos5_list_diable_wfi_wfe[] = {
+static void __iomem *exynos5_list_diable_wfi_wfe[] = {
        EXYNOS5_ARM_CORE1_OPTION,
        EXYNOS5_FSYS_ARM_OPTION,
        EXYNOS5_ISP_ARM_OPTION,
@@ -390,6 +390,8 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
 
 static int __init exynos_pmu_init(void)
 {
+       unsigned int value;
+
        exynos_pmu_config = exynos4210_pmu_config;
 
        if (soc_is_exynos4210()) {
@@ -399,6 +401,18 @@ static int __init exynos_pmu_init(void)
                exynos_pmu_config = exynos4x12_pmu_config;
                pr_info("EXYNOS4x12 PMU Initialize\n");
        } else if (soc_is_exynos5250()) {
+               /*
+                * When SYS_WDTRESET is set, watchdog timer reset request
+                * is ignored by power management unit.
+                */
+               value = __raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE);
+               value &= ~EXYNOS5_SYS_WDTRESET;
+               __raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE);
+
+               value = __raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST);
+               value &= ~EXYNOS5_SYS_WDTRESET;
+               __raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
+
                exynos_pmu_config = exynos5250_pmu_config;
                pr_info("EXYNOS5250 PMU Initialize\n");
        } else {
index 833ff40ee0e8943cd5f711c884f2307df4a52f2d..4999829d1c6eb176f028a4f5959a9af90ac3d66e 100644 (file)
@@ -9,21 +9,10 @@
  */
 
 #include <linux/gpio.h>
-#include <linux/platform_device.h>
-
 #include <plat/gpio-cfg.h>
-#include <plat/s3c64xx-spi.h>
 
 #ifdef CONFIG_S3C64XX_DEV_SPI0
-struct s3c64xx_spi_info s3c64xx_spi0_pdata __initdata = {
-       .fifo_lvl_mask  = 0x1ff,
-       .rx_lvl_offset  = 15,
-       .high_speed     = 1,
-       .clk_from_cmu   = true,
-       .tx_st_done     = 25,
-};
-
-int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi0_cfg_gpio(void)
 {
        s3c_gpio_cfgpin(EXYNOS4_GPB(0), S3C_GPIO_SFN(2));
        s3c_gpio_setpull(EXYNOS4_GPB(0), S3C_GPIO_PULL_UP);
@@ -34,15 +23,7 @@ int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
 #endif
 
 #ifdef CONFIG_S3C64XX_DEV_SPI1
-struct s3c64xx_spi_info s3c64xx_spi1_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 15,
-       .high_speed     = 1,
-       .clk_from_cmu   = true,
-       .tx_st_done     = 25,
-};
-
-int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi1_cfg_gpio(void)
 {
        s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_SFN(2));
        s3c_gpio_setpull(EXYNOS4_GPB(4), S3C_GPIO_PULL_UP);
@@ -53,15 +34,7 @@ int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
 #endif
 
 #ifdef CONFIG_S3C64XX_DEV_SPI2
-struct s3c64xx_spi_info s3c64xx_spi2_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 15,
-       .high_speed     = 1,
-       .clk_from_cmu   = true,
-       .tx_st_done     = 25,
-};
-
-int s3c64xx_spi2_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi2_cfg_gpio(void)
 {
        s3c_gpio_cfgpin(EXYNOS4_GPC1(1), S3C_GPIO_SFN(5));
        s3c_gpio_setpull(EXYNOS4_GPC1(1), S3C_GPIO_PULL_UP);
index 1af0a7f44e002af1c82fec2aee0d2b2cdecba595..b81cc569a8ddab4e7a247752297b1b4fac732542 100644 (file)
@@ -31,27 +31,55 @@ static void exynos4210_usb_phy_clkset(struct platform_device *pdev)
        struct clk *xusbxti_clk;
        u32 phyclk;
 
-       /* set clock frequency for PLL */
-       phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
-
        xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
        if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
-               switch (clk_get_rate(xusbxti_clk)) {
-               case 12 * MHZ:
-                       phyclk |= CLKSEL_12M;
-                       break;
-               case 24 * MHZ:
-                       phyclk |= CLKSEL_24M;
-                       break;
-               default:
-               case 48 * MHZ:
-                       /* default reference clock */
-                       break;
+               if (soc_is_exynos4210()) {
+                       /* set clock frequency for PLL */
+                       phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4210_CLKSEL_MASK;
+
+                       switch (clk_get_rate(xusbxti_clk)) {
+                       case 12 * MHZ:
+                               phyclk |= EXYNOS4210_CLKSEL_12M;
+                               break;
+                       case 48 * MHZ:
+                               phyclk |= EXYNOS4210_CLKSEL_48M;
+                               break;
+                       default:
+                       case 24 * MHZ:
+                               phyclk |= EXYNOS4210_CLKSEL_24M;
+                               break;
+                       }
+                       writel(phyclk, EXYNOS4_PHYCLK);
+               } else if (soc_is_exynos4212() || soc_is_exynos4412()) {
+                       /* set clock frequency for PLL */
+                       phyclk = readl(EXYNOS4_PHYCLK) & ~EXYNOS4X12_CLKSEL_MASK;
+
+                       switch (clk_get_rate(xusbxti_clk)) {
+                       case 9600 * KHZ:
+                               phyclk |= EXYNOS4X12_CLKSEL_9600K;
+                               break;
+                       case 10 * MHZ:
+                               phyclk |= EXYNOS4X12_CLKSEL_10M;
+                               break;
+                       case 12 * MHZ:
+                               phyclk |= EXYNOS4X12_CLKSEL_12M;
+                               break;
+                       case 19200 * KHZ:
+                               phyclk |= EXYNOS4X12_CLKSEL_19200K;
+                               break;
+                       case 20 * MHZ:
+                               phyclk |= EXYNOS4X12_CLKSEL_20M;
+                               break;
+                       default:
+                       case 24 * MHZ:
+                               /* default reference clock */
+                               phyclk |= EXYNOS4X12_CLKSEL_24M;
+                               break;
+                       }
+                       writel(phyclk, EXYNOS4_PHYCLK);
                }
                clk_put(xusbxti_clk);
        }
-
-       writel(phyclk, EXYNOS4_PHYCLK);
 }
 
 static int exynos4210_usb_phy0_init(struct platform_device *pdev)
index eff4db5de0ddb8abbfde826cc14c16b9432c5373..7616101a35f0590addd7cbfe5d88027aba2f1cef 100644 (file)
@@ -52,6 +52,7 @@ config SOC_IMX25
        select ARCH_MX25
        select COMMON_CLK
        select CPU_ARM926T
+       select HAVE_CAN_FLEXCAN if CAN
        select ARCH_MXC_IOMUX_V3
        select MXC_AVIC
 
@@ -73,12 +74,13 @@ config SOC_IMX31
 
 config SOC_IMX35
        bool
-       select CPU_V6
+       select CPU_V6K
        select ARCH_MXC_IOMUX_V3
        select COMMON_CLK
        select HAVE_EPIT
        select MXC_AVIC
        select SMP_ON_UP if SMP
+       select HAVE_CAN_FLEXCAN if CAN
 
 config SOC_IMX5
        select CPU_V7
@@ -105,6 +107,7 @@ config      SOC_IMX53
        select SOC_IMX5
        select ARCH_MX5
        select ARCH_MX53
+       select HAVE_CAN_FLEXCAN if CAN
 
 if ARCH_IMX_V4_V5
 
@@ -158,7 +161,6 @@ config MACH_MX25_3DS
        select IMX_HAVE_PLATFORM_IMX2_WDT
        select IMX_HAVE_PLATFORM_IMXDI_RTC
        select IMX_HAVE_PLATFORM_IMX_I2C
-       select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_FB
        select IMX_HAVE_PLATFORM_IMX_KEYPAD
        select IMX_HAVE_PLATFORM_IMX_UART
@@ -557,6 +559,14 @@ config MACH_BUG
          Include support for BUGBase 1.3 platform. This includes specific
          configurations for the board and its peripherals.
 
+config MACH_IMX31_DT
+       bool "Support i.MX31 platforms from device tree"
+       select SOC_IMX31
+       select USE_OF
+       help
+         Include support for Freescale i.MX31 based platforms
+         using the device tree for discovery.
+
 comment "MX35 platforms:"
 
 config MACH_PCM043
@@ -589,6 +599,7 @@ config MACH_MX35_3DS
        select IMX_HAVE_PLATFORM_IPU_CORE
        select IMX_HAVE_PLATFORM_MXC_EHCI
        select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_MXC_RTC
        select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
        help
          Include support for MX35PDK platform. This includes specific
@@ -826,10 +837,12 @@ config SOC_IMX6Q
        select COMMON_CLK
        select CPU_V7
        select HAVE_ARM_SCU
+       select HAVE_CAN_FLEXCAN if CAN
        select HAVE_IMX_GPC
        select HAVE_IMX_MMDC
        select HAVE_IMX_SRC
        select HAVE_SMP
+       select MFD_ANATOP
        select PINCTRL
        select PINCTRL_IMX6Q
        select USE_OF
index ff29421414f24262e5e4b66c74270f58fa401798..07f7c226e4cfe6eec6181e5e506655223c2f1e1a 100644 (file)
@@ -57,6 +57,7 @@ obj-$(CONFIG_MACH_QONG) += mach-qong.o
 obj-$(CONFIG_MACH_ARMADILLO5X0) += mach-armadillo5x0.o
 obj-$(CONFIG_MACH_KZM_ARM11_01) += mach-kzm_arm11_01.o
 obj-$(CONFIG_MACH_BUG) += mach-bug.o
+obj-$(CONFIG_MACH_IMX31_DT) += imx31-dt.o
 
 # i.MX35 based machines
 obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o
index c9a06d800f8ef7a0a7d96e015cd87754afd09a25..f87a48fc74e18e3f0001b61bea1f9d8954783ab1 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/clkdev.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/of.h>
 
 #include <mach/hardware.h>
 #include <mach/mx31.h>
@@ -179,3 +180,21 @@ int __init mx31_clocks_init(unsigned long fref)
 
        return 0;
 }
+
+#ifdef CONFIG_OF
+int __init mx31_clocks_init_dt(void)
+{
+       struct device_node *np;
+       u32 fref = 26000000; /* default */
+
+       for_each_compatible_node(np, NULL, "fixed-clock") {
+               if (!of_device_is_compatible(np, "fsl,imx-osc26m"))
+                       continue;
+
+               if (!of_property_read_u32(np, "clock-frequency", &fref))
+                       break;
+       }
+
+       return mx31_clocks_init(fref);
+}
+#endif
index 920a8cc4272609829f941432cf9c10b26b979aba..c6422fb10bae37756693f3323f79df62e4fc932e 100644 (file)
@@ -201,7 +201,6 @@ int __init mx35_clocks_init()
                        pr_err("i.MX35 clk %d: register failed with %ld\n",
                                i, PTR_ERR(clk[i]));
 
-
        clk_register_clkdev(clk[pata_gate], NULL, "pata_imx");
        clk_register_clkdev(clk[can1_gate], NULL, "flexcan.0");
        clk_register_clkdev(clk[can2_gate], NULL, "flexcan.1");
@@ -264,6 +263,14 @@ int __init mx35_clocks_init()
        clk_prepare_enable(clk[iim_gate]);
        clk_prepare_enable(clk[emi_gate]);
 
+       /*
+        * SCC is needed to boot via mmc after a watchdog reset. The clock code
+        * before conversion to common clk also enabled UART1 (which isn't
+        * handled here and not needed for mmc) and IIM (which is enabled
+        * unconditionally above).
+        */
+       clk_prepare_enable(clk[scc_gate]);
+
        imx_print_silicon_rev("i.MX35", mx35_revision());
 
 #ifdef CONFIG_MXC_USE_EPIT
index e1a17ac7b3b48419a8ff1f9dadfa5de03f5fd852..ea89520b6e223fd3ab4db3227574c7299605e265 100644 (file)
@@ -147,12 +147,12 @@ enum mx6q_clks {
        esai, gpt_ipg, gpt_ipg_per, gpu2d_core, gpu3d_core, hdmi_iahb,
        hdmi_isfr, i2c1, i2c2, i2c3, iim, enfc, ipu1, ipu1_di0, ipu1_di1, ipu2,
        ipu2_di0, ldb_di0, ldb_di1, ipu2_di1, hsi_tx, mlb, mmdc_ch0_axi,
-       mmdc_ch1_axi, ocram, openvg_axi, pcie_axi, pwm1, pwm2, pwm3, pwm4,
+       mmdc_ch1_axi, ocram, openvg_axi, pcie_axi, pwm1, pwm2, pwm3, pwm4, per1_bch,
        gpmi_bch_apb, gpmi_bch, gpmi_io, gpmi_apb, sata, sdma, spba, ssi1,
        ssi2, ssi3, uart_ipg, uart_serial, usboh3, usdhc1, usdhc2, usdhc3,
        usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg,
        pll4_audio, pll5_video, pll6_mlb, pll7_usb_host, pll8_enet, ssi1_ipg,
-       ssi2_ipg, ssi3_ipg, rom,
+       ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2,
        clk_max
 };
 
@@ -198,6 +198,9 @@ int __init mx6q_clocks_init(void)
        clk[pll7_usb_host] = imx_clk_pllv3(IMX_PLLV3_USB,       "pll7_usb_host","osc", base + 0x20, 0x2000,   0x3);
        clk[pll8_enet]     = imx_clk_pllv3(IMX_PLLV3_ENET,      "pll8_enet",    "osc", base + 0xe0, 0x182000, 0x3);
 
+       clk[usbphy1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 6);
+       clk[usbphy2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 6);
+
        /*                                name              parent_name        reg       idx */
        clk[pll2_pfd0_352m] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus",     base + 0x100, 0);
        clk[pll2_pfd1_594m] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus",     base + 0x100, 1);
@@ -318,7 +321,7 @@ int __init mx6q_clocks_init(void)
        clk[ahb]               = imx_clk_busy_divider("ahb",               "periph",      base + 0x14, 10,  3,   base + 0x48, 1);
 
        /*                                name             parent_name          reg         shift */
-       clk[apbh_dma]     = imx_clk_gate2("apbh_dma",      "ahb",               base + 0x68, 4);
+       clk[apbh_dma]     = imx_clk_gate2("apbh_dma",      "usdhc3",            base + 0x68, 4);
        clk[asrc]         = imx_clk_gate2("asrc",          "asrc_podf",         base + 0x68, 6);
        clk[can1_ipg]     = imx_clk_gate2("can1_ipg",      "ipg",               base + 0x68, 14);
        clk[can1_serial]  = imx_clk_gate2("can1_serial",   "can_root",          base + 0x68, 16);
@@ -357,6 +360,7 @@ int __init mx6q_clocks_init(void)
        clk[ocram]        = imx_clk_gate2("ocram",         "ahb",               base + 0x74, 28);
        clk[openvg_axi]   = imx_clk_gate2("openvg_axi",    "axi",               base + 0x74, 30);
        clk[pcie_axi]     = imx_clk_gate2("pcie_axi",      "pcie_axi_sel",      base + 0x78, 0);
+       clk[per1_bch]     = imx_clk_gate2("per1_bch",      "usdhc3",            base + 0x78, 12);
        clk[pwm1]         = imx_clk_gate2("pwm1",          "ipg_per",           base + 0x78, 16);
        clk[pwm2]         = imx_clk_gate2("pwm2",          "ipg_per",           base + 0x78, 18);
        clk[pwm3]         = imx_clk_gate2("pwm3",          "ipg_per",           base + 0x78, 20);
@@ -388,12 +392,21 @@ int __init mx6q_clocks_init(void)
                        pr_err("i.MX6q clk %d: register failed with %ld\n",
                                i, PTR_ERR(clk[i]));
 
-       clk_register_clkdev(clk[mmdc_ch0_axi], NULL, "mmdc_ch0_axi");
-       clk_register_clkdev(clk[mmdc_ch1_axi], NULL, "mmdc_ch1_axi");
        clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0");
        clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0");
        clk_register_clkdev(clk[twd], NULL, "smp_twd");
-       clk_register_clkdev(clk[usboh3], NULL, "usboh3");
+       clk_register_clkdev(clk[apbh_dma], NULL, "110000.dma-apbh");
+       clk_register_clkdev(clk[per1_bch], "per1_bch", "112000.gpmi-nand");
+       clk_register_clkdev(clk[gpmi_bch_apb], "gpmi_bch_apb", "112000.gpmi-nand");
+       clk_register_clkdev(clk[gpmi_bch], "gpmi_bch", "112000.gpmi-nand");
+       clk_register_clkdev(clk[gpmi_apb], "gpmi_apb", "112000.gpmi-nand");
+       clk_register_clkdev(clk[gpmi_io], "gpmi_io", "112000.gpmi-nand");
+       clk_register_clkdev(clk[usboh3], NULL, "2184000.usb");
+       clk_register_clkdev(clk[usboh3], NULL, "2184200.usb");
+       clk_register_clkdev(clk[usboh3], NULL, "2184400.usb");
+       clk_register_clkdev(clk[usboh3], NULL, "2184600.usb");
+       clk_register_clkdev(clk[usbphy1], NULL, "20c9000.usbphy");
+       clk_register_clkdev(clk[usbphy2], NULL, "20ca000.usbphy");
        clk_register_clkdev(clk[uart_serial], "per", "2020000.serial");
        clk_register_clkdev(clk[uart_ipg], "ipg", "2020000.serial");
        clk_register_clkdev(clk[uart_serial], "per", "21e8000.serial");
index 2628e0c474dc2538f6a5b8c486a80fbabda738c7..93ece55f75dfbf3014039968a6a740d7cecd1900 100644 (file)
@@ -14,7 +14,7 @@ extern const struct imx_imx21_hcd_data imx21_imx21_hcd_data;
        imx_add_imx21_hcd(&imx21_imx21_hcd_data, pdata)
 
 extern const struct imx_imx2_wdt_data imx21_imx2_wdt_data;
-#define imx21_add_imx2_wdt(pdata)      \
+#define imx21_add_imx2_wdt()   \
        imx_add_imx2_wdt(&imx21_imx2_wdt_data)
 
 extern const struct imx_imx_fb_data imx21_imx_fb_data;
@@ -50,7 +50,7 @@ extern const struct imx_mxc_nand_data imx21_mxc_nand_data;
        imx_add_mxc_nand(&imx21_mxc_nand_data, pdata)
 
 extern const struct imx_mxc_w1_data imx21_mxc_w1_data;
-#define imx21_add_mxc_w1(pdata)        \
+#define imx21_add_mxc_w1()     \
        imx_add_mxc_w1(&imx21_mxc_w1_data)
 
 extern const struct imx_spi_imx_data imx21_cspi_data[];
index efa0761c508d7707ddba2f33b6d52f7cffb46cd9..f8e03dd1f116f16a8f175403c6e6cd62756caa2d 100644 (file)
@@ -24,11 +24,11 @@ extern const struct imx_fsl_usb2_udc_data imx25_fsl_usb2_udc_data;
        imx_add_fsl_usb2_udc(&imx25_fsl_usb2_udc_data, pdata)
 
 extern struct imx_imxdi_rtc_data imx25_imxdi_rtc_data;
-#define imx25_add_imxdi_rtc(pdata)     \
+#define imx25_add_imxdi_rtc()  \
        imx_add_imxdi_rtc(&imx25_imxdi_rtc_data)
 
 extern const struct imx_imx2_wdt_data imx25_imx2_wdt_data;
-#define imx25_add_imx2_wdt(pdata)      \
+#define imx25_add_imx2_wdt()   \
        imx_add_imx2_wdt(&imx25_imx2_wdt_data)
 
 extern const struct imx_imx_fb_data imx25_imx_fb_data;
index 28537a5d904801a1c38a8d5bac171bbd2104e9cf..436c5720fe6a40255a2c3bc5ab05378c23855e02 100644 (file)
@@ -18,7 +18,7 @@ extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data;
        imx_add_fsl_usb2_udc(&imx27_fsl_usb2_udc_data, pdata)
 
 extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data;
-#define imx27_add_imx2_wdt(pdata)      \
+#define imx27_add_imx2_wdt()   \
        imx_add_imx2_wdt(&imx27_imx2_wdt_data)
 
 extern const struct imx_imx_fb_data imx27_imx_fb_data;
@@ -50,7 +50,7 @@ extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[];
 extern const struct imx_mx2_camera_data imx27_mx2_camera_data;
 #define imx27_add_mx2_camera(pdata)    \
        imx_add_mx2_camera(&imx27_mx2_camera_data, pdata)
-#define imx27_add_mx2_emmaprp(pdata)   \
+#define imx27_add_mx2_emmaprp()        \
        imx_add_mx2_emmaprp(&imx27_mx2_camera_data)
 
 extern const struct imx_mxc_ehci_data imx27_mxc_ehci_otg_data;
@@ -69,7 +69,7 @@ extern const struct imx_mxc_nand_data imx27_mxc_nand_data;
        imx_add_mxc_nand(&imx27_mxc_nand_data, pdata)
 
 extern const struct imx_mxc_w1_data imx27_mxc_w1_data;
-#define imx27_add_mxc_w1(pdata)        \
+#define imx27_add_mxc_w1()     \
        imx_add_mxc_w1(&imx27_mxc_w1_data)
 
 extern const struct imx_spi_imx_data imx27_cspi_data[];
index 488e241a6db638b90f2da3ca38108cb0eea42a8b..13f533d0aa5c5643096c7a6bfa23e3615a111fa8 100644 (file)
@@ -14,7 +14,7 @@ extern const struct imx_fsl_usb2_udc_data imx31_fsl_usb2_udc_data;
        imx_add_fsl_usb2_udc(&imx31_fsl_usb2_udc_data, pdata)
 
 extern const struct imx_imx2_wdt_data imx31_imx2_wdt_data;
-#define imx31_add_imx2_wdt(pdata)       \
+#define imx31_add_imx2_wdt()       \
        imx_add_imx2_wdt(&imx31_imx2_wdt_data)
 
 extern const struct imx_imx_i2c_data imx31_imx_i2c_data[];
@@ -65,11 +65,11 @@ extern const struct imx_mxc_nand_data imx31_mxc_nand_data;
        imx_add_mxc_nand(&imx31_mxc_nand_data, pdata)
 
 extern const struct imx_mxc_rtc_data imx31_mxc_rtc_data;
-#define imx31_add_mxc_rtc(pdata)       \
+#define imx31_add_mxc_rtc()    \
        imx_add_mxc_rtc(&imx31_mxc_rtc_data)
 
 extern const struct imx_mxc_w1_data imx31_mxc_w1_data;
-#define imx31_add_mxc_w1(pdata)        \
+#define imx31_add_mxc_w1()     \
        imx_add_mxc_w1(&imx31_mxc_w1_data)
 
 extern const struct imx_spi_imx_data imx31_cspi_data[];
index 7b99ef0bb50111f24fb97a0aca09a3a3517cabc3..4815be1ee67560c55621d9d1aa058ad08e38d181 100644 (file)
@@ -24,7 +24,7 @@ extern const struct imx_flexcan_data imx35_flexcan_data[];
 #define imx35_add_flexcan1(pdata)      imx35_add_flexcan(1, pdata)
 
 extern const struct imx_imx2_wdt_data imx35_imx2_wdt_data;
-#define imx35_add_imx2_wdt(pdata)       \
+#define imx35_add_imx2_wdt()       \
        imx_add_imx2_wdt(&imx35_imx2_wdt_data)
 
 extern const struct imx_imx_i2c_data imx35_imx_i2c_data[];
@@ -68,8 +68,12 @@ extern const struct imx_mxc_nand_data imx35_mxc_nand_data;
 #define imx35_add_mxc_nand(pdata)      \
        imx_add_mxc_nand(&imx35_mxc_nand_data, pdata)
 
+extern const struct imx_mxc_rtc_data imx35_mxc_rtc_data;
+#define imx35_add_mxc_rtc()    \
+       imx_add_mxc_rtc(&imx35_mxc_rtc_data)
+
 extern const struct imx_mxc_w1_data imx35_mxc_w1_data;
-#define imx35_add_mxc_w1(pdata)        \
+#define imx35_add_mxc_w1()     \
        imx_add_mxc_w1(&imx35_mxc_w1_data)
 
 extern const struct imx_sdhci_esdhc_imx_data imx35_sdhci_esdhc_imx_data[];
index af488bc0e2256df020b37c770f534bcc0cde01e1..9f1718725195414e0798a40d49c932838f7b4235 100644 (file)
@@ -55,7 +55,7 @@ extern const struct imx_spi_imx_data imx51_ecspi_data[];
        imx_add_spi_imx(&imx51_ecspi_data[id], pdata)
 
 extern const struct imx_imx2_wdt_data imx51_imx2_wdt_data[];
-#define imx51_add_imx2_wdt(id, pdata)  \
+#define imx51_add_imx2_wdt(id) \
        imx_add_imx2_wdt(&imx51_imx2_wdt_data[id])
 
 extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[];
index 6e1e5d1f8c3a9886cd40f47c29e768431d5b416d..77e0db96c4483c4592099fb7639678a180f84190 100644 (file)
@@ -30,7 +30,7 @@ extern const struct imx_spi_imx_data imx53_ecspi_data[];
        imx_add_spi_imx(&imx53_ecspi_data[id], pdata)
 
 extern const struct imx_imx2_wdt_data imx53_imx2_wdt_data[];
-#define imx53_add_imx2_wdt(id, pdata)  \
+#define imx53_add_imx2_wdt(id) \
        imx_add_imx2_wdt(&imx53_imx2_wdt_data[id])
 
 extern const struct imx_imx_ssi_data imx53_imx_ssi_data[];
index 865daf0b09e97e0dfa50721096a30dbe1ec0358d..05bb41d99728b3911ea6cfb8203a08cece9bdba7 100644 (file)
 #define MX25_OTG_SIC_SHIFT     29
 #define MX25_OTG_SIC_MASK      (0x3 << MX25_OTG_SIC_SHIFT)
 #define MX25_OTG_PM_BIT                (1 << 24)
+#define MX25_OTG_PP_BIT                (1 << 11)
+#define MX25_OTG_OCPOL_BIT     (1 << 3)
 
 #define MX25_H1_SIC_SHIFT      21
 #define MX25_H1_SIC_MASK       (0x3 << MX25_H1_SIC_SHIFT)
+#define MX25_H1_PP_BIT         (1 << 18)
 #define MX25_H1_PM_BIT         (1 << 8)
 #define MX25_H1_IPPUE_UP_BIT   (1 << 7)
 #define MX25_H1_IPPUE_DOWN_BIT (1 << 6)
 #define MX25_H1_TLL_BIT                (1 << 5)
 #define MX25_H1_USBTE_BIT      (1 << 4)
+#define MX25_H1_OCPOL_BIT      (1 << 2)
 
 int mx25_initialize_usb_hw(int port, unsigned int flags)
 {
@@ -41,21 +45,35 @@ int mx25_initialize_usb_hw(int port, unsigned int flags)
 
        switch (port) {
        case 0: /* OTG port */
-               v &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PM_BIT);
+               v &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PM_BIT | MX25_OTG_PP_BIT |
+                       MX25_OTG_OCPOL_BIT);
                v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
 
                if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
                        v |= MX25_OTG_PM_BIT;
 
+               if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+                       v |= MX25_OTG_PP_BIT;
+
+               if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+                       v |= MX25_OTG_OCPOL_BIT;
+
                break;
        case 1: /* H1 port */
-               v &= ~(MX25_H1_SIC_MASK | MX25_H1_PM_BIT | MX25_H1_TLL_BIT |
-                       MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT | MX25_H1_IPPUE_UP_BIT);
+               v &= ~(MX25_H1_SIC_MASK | MX25_H1_PM_BIT | MX25_H1_PP_BIT |
+                       MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | MX25_H1_USBTE_BIT |
+                       MX25_H1_IPPUE_DOWN_BIT | MX25_H1_IPPUE_UP_BIT);
                v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
 
                if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
                        v |= MX25_H1_PM_BIT;
 
+               if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+                       v |= MX25_H1_PP_BIT;
+
+               if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+                       v |= MX25_H1_OCPOL_BIT;
+
                if (!(flags & MXC_EHCI_TTL_ENABLED))
                        v |= MX25_H1_TLL_BIT;
 
index 001ec3971f5da93de19c7e2db9153a32f4347348..73574c30cf50ca97c337eaa4ec9bd58d7a2c9dab 100644 (file)
 #define MX35_OTG_SIC_SHIFT     29
 #define MX35_OTG_SIC_MASK      (0x3 << MX35_OTG_SIC_SHIFT)
 #define MX35_OTG_PM_BIT                (1 << 24)
+#define MX35_OTG_PP_BIT                (1 << 11)
+#define MX35_OTG_OCPOL_BIT     (1 << 3)
 
 #define MX35_H1_SIC_SHIFT      21
 #define MX35_H1_SIC_MASK       (0x3 << MX35_H1_SIC_SHIFT)
+#define MX35_H1_PP_BIT         (1 << 18)
 #define MX35_H1_PM_BIT         (1 << 8)
 #define MX35_H1_IPPUE_UP_BIT   (1 << 7)
 #define MX35_H1_IPPUE_DOWN_BIT (1 << 6)
 #define MX35_H1_TLL_BIT                (1 << 5)
 #define MX35_H1_USBTE_BIT      (1 << 4)
+#define MX35_H1_OCPOL_BIT      (1 << 2)
 
 int mx35_initialize_usb_hw(int port, unsigned int flags)
 {
@@ -41,21 +45,35 @@ int mx35_initialize_usb_hw(int port, unsigned int flags)
 
        switch (port) {
        case 0: /* OTG port */
-               v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT);
+               v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT | MX35_OTG_PP_BIT |
+                       MX35_OTG_OCPOL_BIT);
                v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_OTG_SIC_SHIFT;
 
                if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
                        v |= MX35_OTG_PM_BIT;
 
+               if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+                       v |= MX35_OTG_PP_BIT;
+
+               if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+                       v |= MX35_OTG_OCPOL_BIT;
+
                break;
        case 1: /* H1 port */
-               v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_TLL_BIT |
-                       MX35_H1_USBTE_BIT | MX35_H1_IPPUE_DOWN_BIT | MX35_H1_IPPUE_UP_BIT);
+               v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_PP_BIT |
+                       MX35_H1_OCPOL_BIT | MX35_H1_TLL_BIT | MX35_H1_USBTE_BIT |
+                       MX35_H1_IPPUE_DOWN_BIT | MX35_H1_IPPUE_UP_BIT);
                v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_H1_SIC_SHIFT;
 
                if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
                        v |= MX35_H1_PM_BIT;
 
+               if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+                       v |= MX35_H1_PP_BIT;
+
+               if (!(flags & MXC_EHCI_OC_PIN_ACTIVE_LOW))
+                       v |= MX35_H1_OCPOL_BIT;
+
                if (!(flags & MXC_EHCI_TTL_ENABLED))
                        v |= MX35_H1_TLL_BIT;
 
index c17fa131728b227dcbc44a3ede131e58a12919ee..a6a4afb0ad62d8a6738d70cc81137b5a2f014571 100644 (file)
 #define MXC_OTG_UCTRL_OPM_BIT          (1 << 24)       /* OTG power mask */
 #define MXC_H1_UCTRL_H1UIE_BIT         (1 << 12)       /* Host1 ULPI interrupt enable */
 #define MXC_H1_UCTRL_H1WIE_BIT         (1 << 11)       /* HOST1 wakeup intr enable */
-#define MXC_H1_UCTRL_H1PM_BIT          (1 <<  8)               /* HOST1 power mask */
+#define MXC_H1_UCTRL_H1PM_BIT          (1 <<  8)       /* HOST1 power mask */
 
 /* USB_PHY_CTRL_FUNC */
+#define MXC_OTG_PHYCTRL_OC_POL_BIT     (1 << 9)        /* OTG Polarity of Overcurrent */
 #define MXC_OTG_PHYCTRL_OC_DIS_BIT     (1 << 8)        /* OTG Disable Overcurrent Event */
+#define MXC_H1_OC_POL_BIT              (1 << 6)        /* UH1 Polarity of Overcurrent */
 #define MXC_H1_OC_DIS_BIT              (1 << 5)        /* UH1 Disable Overcurrent Event */
+#define MXC_OTG_PHYCTRL_PWR_POL_BIT    (1 << 3)        /* OTG Power Pin Polarity */
 
 /* USBH2CTRL */
 #define MXC_H2_UCTRL_H2UIE_BIT         (1 << 8)
@@ -80,13 +83,21 @@ int mx51_initialize_usb_hw(int port, unsigned int flags)
                if (flags & MXC_EHCI_INTERNAL_PHY) {
                        v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
 
+                       if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW)
+                               v |= MXC_OTG_PHYCTRL_OC_POL_BIT;
+                       else
+                               v &= ~MXC_OTG_PHYCTRL_OC_POL_BIT;
                        if (flags & MXC_EHCI_POWER_PINS_ENABLED) {
-                               /* OC/USBPWR is not used */
-                               v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
-                       } else {
                                /* OC/USBPWR is used */
                                v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT;
+                       } else {
+                               /* OC/USBPWR is not used */
+                               v |= MXC_OTG_PHYCTRL_OC_DIS_BIT;
                        }
+                       if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH)
+                               v |= MXC_OTG_PHYCTRL_PWR_POL_BIT;
+                       else
+                               v &= ~MXC_OTG_PHYCTRL_PWR_POL_BIT;
                        __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
 
                        v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET);
@@ -95,9 +106,9 @@ int mx51_initialize_usb_hw(int port, unsigned int flags)
                        else
                                v &= ~MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup disable */
                        if (flags & MXC_EHCI_POWER_PINS_ENABLED)
-                               v |= MXC_OTG_UCTRL_OPM_BIT;
-                       else
                                v &= ~MXC_OTG_UCTRL_OPM_BIT;
+                       else
+                               v |= MXC_OTG_UCTRL_OPM_BIT;
                        __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
                }
                break;
@@ -113,12 +124,16 @@ int mx51_initialize_usb_hw(int port, unsigned int flags)
                }
 
                if (flags & MXC_EHCI_POWER_PINS_ENABLED)
-                       v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
+                       v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask unused*/
                else
                        v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/
                __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET);
 
                v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET);
+               if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW)
+                       v |= MXC_H1_OC_POL_BIT;
+               else
+                       v &= ~MXC_H1_OC_POL_BIT;
                if (flags & MXC_EHCI_POWER_PINS_ENABLED)
                        v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */
                else
@@ -142,7 +157,7 @@ int mx51_initialize_usb_hw(int port, unsigned int flags)
                }
 
                if (flags & MXC_EHCI_POWER_PINS_ENABLED)
-                       v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/
+                       v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask unused*/
                else
                        v |= MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/
                __raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET);
index eee0cc8d92a43e84300723b05e6e9bb86bcb84f1..52efe4d5149b5c3486ce8faeb7cfc2c0b9f90618 100644 (file)
@@ -75,7 +75,7 @@ static struct sys_timer imx27_timer = {
        .init = imx27_timer_init,
 };
 
-static const char *imx27_dt_board_compat[] __initdata = {
+static const char * const imx27_dt_board_compat[] __initconst = {
        "fsl,imx27",
        NULL
 };
diff --git a/arch/arm/mach-imx/imx31-dt.c b/arch/arm/mach-imx/imx31-dt.c
new file mode 100644 (file)
index 0000000..a68ba20
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012 Sascha Hauer, Pengutronix
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+#include <mach/mx31.h>
+
+static const struct of_dev_auxdata imx31_auxdata_lookup[] __initconst = {
+       OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART1_BASE_ADDR,
+                       "imx21-uart.0", NULL),
+       OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART2_BASE_ADDR,
+                       "imx21-uart.1", NULL),
+       OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART3_BASE_ADDR,
+                       "imx21-uart.2", NULL),
+       OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART4_BASE_ADDR,
+                       "imx21-uart.3", NULL),
+       OF_DEV_AUXDATA("fsl,imx31-uart", MX31_UART5_BASE_ADDR,
+                       "imx21-uart.4", NULL),
+       { /* sentinel */ }
+};
+
+static void __init imx31_dt_init(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            imx31_auxdata_lookup, NULL);
+}
+
+static void __init imx31_timer_init(void)
+{
+       mx31_clocks_init_dt();
+}
+
+static struct sys_timer imx31_timer = {
+       .init = imx31_timer_init,
+};
+
+static const char *imx31_dt_board_compat[] __initdata = {
+       "fsl,imx31",
+       NULL
+};
+
+DT_MACHINE_START(IMX31_DT, "Freescale i.MX31 (Device Tree Support)")
+       .map_io         = mx31_map_io,
+       .init_early     = imx31_init_early,
+       .init_irq       = mx31_init_irq,
+       .handle_irq     = imx31_handle_irq,
+       .timer          = &imx31_timer,
+       .init_machine   = imx31_dt_init,
+       .dt_compat      = imx31_dt_board_compat,
+       .restart        = mxc_restart,
+MACHINE_END
index d085aea087095e4750e104a54aaee02c7312b0cf..9a3b06e688c509aee812017f493e44eb4cc64338 100644 (file)
@@ -233,18 +233,18 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init eukrea_cpuimx27_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", eukrea_cpuimx27_otg_mode);
 
@@ -266,8 +266,8 @@ static void __init eukrea_cpuimx27_init(void)
 
        imx27_add_fec(NULL);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
-       imx27_add_imx2_wdt(NULL);
-       imx27_add_mxc_w1(NULL);
+       imx27_add_imx2_wdt();
+       imx27_add_mxc_w1();
 
 #if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2)
        /* SDHC2 can be used for Wifi */
index 6450303f1a7ac01e701adf8b886248a981c54856..1634e54ffed5594833a0428c2779cfea89031f38 100644 (file)
@@ -141,18 +141,18 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .workaround     = FLS_USB2_WORKAROUND_ENGCM09152,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init eukrea_cpuimx35_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", eukrea_cpuimx35_otg_mode);
 
@@ -167,7 +167,7 @@ static void __init eukrea_cpuimx35_init(void)
                        ARRAY_SIZE(eukrea_cpuimx35_pads));
 
        imx35_add_fec(NULL);
-       imx35_add_imx2_wdt(NULL);
+       imx35_add_imx2_wdt();
 
        imx35_add_imx_uart0(&uart_pdata);
        imx35_add_mxc_nand(&eukrea_cpuimx35_nand_board_info);
index 1e09de50cbcdc9292ad762d6228c7663fbfcc4a2..e78b40b4146249cdfb8f93624d9c2e4f125359e6 100644 (file)
@@ -217,18 +217,18 @@ static const struct mxc_usbh_platform_data usbh1_config __initconst = {
        .portsc = MXC_EHCI_MODE_ULPI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init eukrea_cpuimx51sd_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", eukrea_cpuimx51sd_otg_mode);
 
@@ -292,7 +292,7 @@ static void __init eukrea_cpuimx51sd_init(void)
 
        imx51_add_imx_uart(0, &uart_pdata);
        imx51_add_mxc_nand(&eukrea_cpuimx51sd_nand_board_info);
-       imx51_add_imx2_wdt(0, NULL);
+       imx51_add_imx2_wdt(0);
 
        gpio_request(ETH_RST, "eth_rst");
        gpio_set_value(ETH_RST, 1);
index d1e04e676e33b0cb4c516560d72c61030c64a5bd..017bbb70ea415b3b75c050dbf0952aa46374680c 100644 (file)
@@ -109,18 +109,18 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .workaround     = FLS_USB2_WORKAROUND_ENGCM09152,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init eukrea_cpuimx25_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", eukrea_cpuimx25_otg_mode);
 
@@ -134,9 +134,9 @@ static void __init eukrea_cpuimx25_init(void)
 
        imx25_add_imx_uart0(&uart_pdata);
        imx25_add_mxc_nand(&eukrea_cpuimx25_nand_board_info);
-       imx25_add_imxdi_rtc(NULL);
+       imx25_add_imxdi_rtc();
        imx25_add_fec(&mx25_fec_pdata);
-       imx25_add_imx2_wdt(NULL);
+       imx25_add_imx2_wdt();
 
        i2c_register_board_info(0, eukrea_cpuimx25_i2c_devices,
                                ARRAY_SIZE(eukrea_cpuimx25_i2c_devices));
index f76edb96a48a671322f7a6c30935cfa524477463..ba09552fe5feee5b6720e3b294449e6d46bfeddf 100644 (file)
@@ -38,7 +38,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
-#include <asm/system.h>
+#include <asm/system_info.h>
 #include <mach/common.h>
 #include <mach/iomux-mx27.h>
 
index c9d350c5dcc83a590ea36774887eb7fd8461e72b..7381387a890558909ae69b3fd2fbeb621118e61c 100644 (file)
@@ -57,7 +57,7 @@ static void __init mx27ipcam_init(void)
 
        imx27_add_imx_uart0(NULL);
        imx27_add_fec(NULL);
-       imx27_add_imx2_wdt(NULL);
+       imx27_add_imx2_wdt();
 }
 
 static void __init mx27ipcam_timer_init(void)
index b47e98b7d539fc9bce4cd4f0060004f086d528c4..140f55010630ffb8b17fd7ed858cbe5dff0f14f0 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/phy.h>
 #include <linux/micrel_phy.h>
+#include <linux/mfd/anatop.h>
 #include <asm/smp_twd.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
@@ -113,6 +114,45 @@ static void __init imx6q_sabrelite_init(void)
        imx6q_sabrelite_cko1_setup();
 }
 
+static void __init imx6q_usb_init(void)
+{
+       struct device_node *np;
+       struct platform_device *pdev = NULL;
+       struct anatop *adata = NULL;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
+       if (np)
+               pdev = of_find_device_by_node(np);
+       if (pdev)
+               adata = platform_get_drvdata(pdev);
+       if (!adata) {
+               if (np)
+                       of_node_put(np);
+               return;
+       }
+
+#define HW_ANADIG_USB1_CHRG_DETECT             0x000001b0
+#define HW_ANADIG_USB2_CHRG_DETECT             0x00000210
+
+#define BM_ANADIG_USB_CHRG_DETECT_EN_B         0x00100000
+#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B   0x00080000
+
+       /*
+        * The external charger detector needs to be disabled,
+        * or the signal at DP will be poor
+        */
+       anatop_write_reg(adata, HW_ANADIG_USB1_CHRG_DETECT,
+                       BM_ANADIG_USB_CHRG_DETECT_EN_B
+                       | BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
+                       ~0);
+       anatop_write_reg(adata, HW_ANADIG_USB2_CHRG_DETECT,
+                       BM_ANADIG_USB_CHRG_DETECT_EN_B |
+                       BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B,
+                       ~0);
+
+       of_node_put(np);
+}
+
 static void __init imx6q_init_machine(void)
 {
        /*
@@ -127,6 +167,7 @@ static void __init imx6q_init_machine(void)
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 
        imx6q_pm_init();
+       imx6q_usb_init();
 }
 
 static void __init imx6q_map_io(void)
index f26734298aa629d52c94faea8f7e7ea2a0694230..ce247fd1269ae094a57dc95065ba2256effb7e65 100644 (file)
@@ -237,9 +237,9 @@ static void __init mx25pdk_init(void)
        imx25_add_fsl_usb2_udc(&otg_device_pdata);
        imx25_add_mxc_ehci_hs(&usbh2_pdata);
        imx25_add_mxc_nand(&mx25pdk_nand_board_info);
-       imx25_add_imxdi_rtc(NULL);
+       imx25_add_imxdi_rtc();
        imx25_add_imx_fb(&mx25pdk_fb_pdata);
-       imx25_add_imx2_wdt(NULL);
+       imx25_add_imx2_wdt();
 
        mx25pdk_fec_reset();
        imx25_add_fec(&mx25_fec_pdata);
index c6d385c522576f1052eeb474fc2d69a86faa7a0e..ce9a5c26290c07a2d7ebac12116af4ff6a62ac76 100644 (file)
@@ -241,18 +241,18 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init mx27_3ds_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", mx27_3ds_otg_mode);
 
@@ -480,7 +480,7 @@ static void __init mx27pdk_init(void)
        imx27_add_fec(NULL);
        imx27_add_imx_keypad(&mx27_3ds_keymap_data);
        imx27_add_mxc_mmc(0, &sdhc1_pdata);
-       imx27_add_imx2_wdt(NULL);
+       imx27_add_imx2_wdt();
        otg_phy_init();
 
        if (otg_mode_host) {
index 0228d2e07fe05ed641b6f24988b0730b9eae86ed..7936bb32264da65a5f3874438e1f50bfd3b47965 100644 (file)
@@ -310,7 +310,7 @@ static void __init mx27ads_board_init(void)
 
        imx27_add_fec(NULL);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
-       imx27_add_mxc_w1(NULL);
+       imx27_add_mxc_w1();
 }
 
 static void __init mx27ads_timer_init(void)
index 4eafdf275ea28864d6dacf6667be7221cf2a9a22..928e1dcbc6a701eccbb8940a53fba02338feda63 100644 (file)
@@ -671,18 +671,18 @@ static const struct fsl_usb2_platform_data usbotg_pdata __initconst = {
        .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init mx31_3ds_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", mx31_3ds_otg_mode);
 
@@ -739,7 +739,7 @@ static void __init mx31_3ds_init(void)
        if (mxc_expio_init(MX31_CS5_BASE_ADDR, EXPIO_PARENT_INT))
                printk(KERN_WARNING "Init of the debug board failed, all "
                                    "devices on the debug board are unusable.\n");
-       imx31_add_imx2_wdt(NULL);
+       imx31_add_imx2_wdt();
        imx31_add_imx_i2c0(&mx31_3ds_i2c0_data);
        imx31_add_mxc_mmc(0, &sdhc1_pdata);
 
index 016791f038b0a75e918077cecf4ecaff5452cabf..63e84e67b990cc7d1b7455088ce85bf75e66c71b 100644 (file)
@@ -544,7 +544,7 @@ static void __init mx31moboard_init(void)
        platform_add_devices(devices, ARRAY_SIZE(devices));
        gpio_led_register_device(-1, &mx31moboard_led_pdata);
 
-       imx31_add_imx2_wdt(NULL);
+       imx31_add_imx2_wdt();
 
        imx31_add_imx_uart0(&uart0_pdata);
        imx31_add_imx_uart4(&uart4_pdata);
index 28aa19476de73dc47ea40eaec323e71e1623b7e7..69018e5c52ded009cc24724c098ff42f432e7e3f 100644 (file)
@@ -540,18 +540,18 @@ static const struct mxc_usbh_platform_data usb_host_pdata __initconst = {
        .portsc         = MXC_EHCI_MODE_SERIAL,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init mx35_3ds_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", mx35_3ds_otg_mode);
 
@@ -571,7 +571,8 @@ static void __init mx35_3ds_init(void)
        mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
 
        imx35_add_fec(NULL);
-       imx35_add_imx2_wdt(NULL);
+       imx35_add_imx2_wdt();
+       imx35_add_mxc_rtc();
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        imx35_add_imx_uart0(&uart_pdata);
index 3c5b163923f63e4b20ab311fee76a70bb431d666..2edb563b968d5404315974e4f360ba4c8d64ccd7 100644 (file)
@@ -154,7 +154,7 @@ static void __init mx51_3ds_init(void)
 
        imx51_add_sdhci_esdhc_imx(0, NULL);
        imx51_add_imx_keypad(&mx51_3ds_map_data);
-       imx51_add_imx2_wdt(0, NULL);
+       imx51_add_imx2_wdt(0);
 }
 
 static void __init mx51_3ds_timer_init(void)
index dde397014d4b709d2cd2026d8ea879676f3b35b8..7b31cbde8775409312da8d8b749c293c3ced850f 100644 (file)
@@ -307,18 +307,18 @@ static const struct mxc_usbh_platform_data usbh1_config __initconst = {
        .portsc = MXC_EHCI_MODE_ULPI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init babbage_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", babbage_otg_mode);
 
@@ -411,7 +411,7 @@ static void __init mx51_babbage_init(void)
        spi_register_board_info(mx51_babbage_spi_board_info,
                ARRAY_SIZE(mx51_babbage_spi_board_info));
        imx51_add_ecspi(0, &mx51_babbage_spi_pdata);
-       imx51_add_imx2_wdt(0, NULL);
+       imx51_add_imx2_wdt(0);
 }
 
 static void __init mx51_babbage_timer_init(void)
index 05641980dc5e7c86ede296ef01129be70fea653b..4a7593a953e29513717e2af90fe5fb38a9852c90 100644 (file)
@@ -243,7 +243,7 @@ static void __init mx53_ard_board_init(void)
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        imx53_add_sdhci_esdhc_imx(0, &mx53_ard_sd1_data);
-       imx53_add_imx2_wdt(0, NULL);
+       imx53_add_imx2_wdt(0);
        imx53_add_imx_i2c(1, &mx53_ard_i2c2_data);
        imx53_add_imx_i2c(2, &mx53_ard_i2c3_data);
        imx_add_gpio_keys(&ard_button_data);
index 5a72188b9cdb6e3ba8479a7b473c04a77d92080d..a1060b26fb23b4864004df6ec87a727306bac253 100644 (file)
@@ -154,7 +154,7 @@ static void __init mx53_evk_board_init(void)
        spi_register_board_info(mx53_evk_spi_board_info,
                ARRAY_SIZE(mx53_evk_spi_board_info));
        imx53_add_ecspi(0, &mx53_evk_spi_data);
-       imx53_add_imx2_wdt(0, NULL);
+       imx53_add_imx2_wdt(0);
        gpio_led_register_device(-1, &mx53evk_leds_data);
 }
 
index 37f67cac15a4daad2d803266503f6b2dfa81d4d0..388c415d6b62c4b45d575f81f863a0e66ba53f71 100644 (file)
@@ -283,7 +283,7 @@ static void __init mx53_loco_board_init(void)
        imx53_add_imx_uart(0, NULL);
        mx53_loco_fec_reset();
        imx53_add_fec(&mx53_loco_fec_data);
-       imx53_add_imx2_wdt(0, NULL);
+       imx53_add_imx2_wdt(0);
 
        ret = gpio_request_one(LOCO_ACCEL_EN, GPIOF_OUT_INIT_HIGH, "accel_en");
        if (ret)
index 8e972c5c3e138bfebe6244b3da450937d1ede945..f297df7ccb39cef69f16c4c8cbf93a49ed144833 100644 (file)
@@ -138,7 +138,7 @@ static void __init mx53_smd_board_init(void)
        mx53_smd_init_uart();
        mx53_smd_fec_reset();
        imx53_add_fec(&mx53_smd_fec_data);
-       imx53_add_imx2_wdt(0, NULL);
+       imx53_add_imx2_wdt(0);
        imx53_add_imx_i2c(0, &mx53_smd_i2c_data);
        imx53_add_sdhci_esdhc_imx(0, NULL);
        imx53_add_sdhci_esdhc_imx(1, NULL);
index 541152e450c420bbf2cd65ca6061bee935957191..d37ed25003b20778d11dda83529a93c170fc033a 100644 (file)
@@ -298,18 +298,18 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init pca100_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", pca100_otg_mode);
 
@@ -408,8 +408,8 @@ static void __init pca100_init(void)
        imx27_add_imx_fb(&pca100_fb_data);
 
        imx27_add_fec(NULL);
-       imx27_add_imx2_wdt(NULL);
-       imx27_add_mxc_w1(NULL);
+       imx27_add_imx2_wdt();
+       imx27_add_mxc_w1();
 }
 
 static void __init pca100_timer_init(void)
index 0a40004154f234e4afba7f20477a902509bb6637..cd48712a6f50abbe2af7bacb1ad1a1c428a54fe3 100644 (file)
@@ -557,18 +557,18 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .phy_mode       = FSL_USB2_PHY_ULPI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init pcm037_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", pcm037_otg_mode);
 
@@ -619,13 +619,13 @@ static void __init pcm037_init(void)
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       imx31_add_imx2_wdt(NULL);
+       imx31_add_imx2_wdt();
        imx31_add_imx_uart0(&uart_pdata);
        /* XXX: should't this have .flags = 0 (i.e. no RTSCTS) on PCM037_EET? */
        imx31_add_imx_uart1(&uart_pdata);
        imx31_add_imx_uart2(&uart_pdata);
 
-       imx31_add_mxc_w1(NULL);
+       imx31_add_mxc_w1();
 
        /* LAN9217 IRQ pin */
        ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1), "lan9217-irq");
index 2f3debe2a11335f60de6f2913cb4ba9452127567..3fbb89d74fccc1f23774e30e6ec1ae927678a889 100644 (file)
@@ -332,8 +332,8 @@ static void __init pcm038_init(void)
 
        imx27_add_fec(NULL);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
-       imx27_add_imx2_wdt(NULL);
-       imx27_add_mxc_w1(NULL);
+       imx27_add_imx2_wdt();
+       imx27_add_mxc_w1();
 
 #ifdef CONFIG_MACH_PCM970_BASEBOARD
        pcm970_baseboard_init();
index 73585f55cca0c6b804351064511a69b678fc1a63..1f20f222375ed86fde1e86594907413c905a2849 100644 (file)
@@ -330,18 +330,18 @@ static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
        .phy_mode       = FSL_USB2_PHY_UTMI,
 };
 
-static int otg_mode_host;
+static bool otg_mode_host __initdata;
 
 static int __init pcm043_otg_mode(char *options)
 {
        if (!strcmp(options, "host"))
-               otg_mode_host = 1;
+               otg_mode_host = true;
        else if (!strcmp(options, "device"))
-               otg_mode_host = 0;
+               otg_mode_host = false;
        else
                pr_info("otg_mode neither \"host\" nor \"device\". "
                        "Defaulting to device\n");
-       return 0;
+       return 1;
 }
 __setup("otg_mode=", pcm043_otg_mode);
 
@@ -363,7 +363,7 @@ static void __init pcm043_init(void)
 
        imx35_add_fec(NULL);
        platform_add_devices(devices, ARRAY_SIZE(devices));
-       imx35_add_imx2_wdt(NULL);
+       imx35_add_imx2_wdt();
 
        imx35_add_imx_uart0(&uart_pdata);
        imx35_add_mxc_nand(&pcm037_nand_board_info);
index 260621055b6be1edfe9ef4ce8eca2f391d3edb86..a13087b11a6e5064ed653cc4ee87ce6fd528a285 100644 (file)
@@ -252,7 +252,7 @@ static void __init qong_init(void)
        mxc_init_imx_uart();
        qong_init_nor_mtd();
        qong_init_fpga();
-       imx31_add_imx2_wdt(NULL);
+       imx31_add_imx2_wdt();
 }
 
 static void __init qong_timer_init(void)
index add8c69c6c1ade1e8c020d03166d25365cf7e532..b26209d4bcef1bf725ee2deda236787d5be087ab 100644 (file)
@@ -272,7 +272,7 @@ static void __init vpr200_board_init(void)
        mxc_iomux_v3_setup_multiple_pads(vpr200_pads, ARRAY_SIZE(vpr200_pads));
 
        imx35_add_fec(NULL);
-       imx35_add_imx2_wdt(NULL);
+       imx35_add_imx2_wdt();
        imx_add_gpio_keys(&vpr200_gpio_keys_data);
 
        platform_add_devices(devices, ARRAY_SIZE(devices));
index bf0fb87946ba40fbd1a0ee5222572034177ccc68..fa60ef6ac7ff6776e5f8061cdd9fb26a3ed68e02 100644 (file)
@@ -191,6 +191,6 @@ void __init mx31lite_db_init(void)
        imx31_add_mxc_mmc(0, &mmc_pdata);
        imx31_add_spi_imx0(&spi0_pdata);
        gpio_led_register_device(-1, &litekit_led_platform_data);
-       imx31_add_imx2_wdt(NULL);
-       imx31_add_mxc_rtc(NULL);
+       imx31_add_imx2_wdt();
+       imx31_add_mxc_rtc();
 }
diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig
deleted file mode 100644 (file)
index e0b3eee..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-if ARCH_LPC32XX
-
-menu "Individual UART enable selections"
-
-config ARCH_LPC32XX_UART3_SELECT
-       bool "Add support for standard UART3"
-       help
-        Adds support for standard UART 3 when the 8250 serial support
-        is enabled.
-
-config ARCH_LPC32XX_UART4_SELECT
-       bool "Add support for standard UART4"
-       help
-        Adds support for standard UART 4 when the 8250 serial support
-        is enabled.
-
-config ARCH_LPC32XX_UART5_SELECT
-       bool "Add support for standard UART5"
-       default y
-       help
-        Adds support for standard UART 5 when the 8250 serial support
-        is enabled.
-
-config ARCH_LPC32XX_UART6_SELECT
-       bool "Add support for standard UART6"
-       help
-        Adds support for standard UART 6 when the 8250 serial support
-        is enabled.
-
-endmenu
-
-endif
index 2cfe0ee635c55ba844e93aedb64a477d2572d25a..697323b5f92d4033d3a48bfcca542b21428f12be 100644 (file)
@@ -2,3 +2,4 @@
 params_phys-y  := 0x80000100
 initrd_phys-y  := 0x82000000
 
+dtb-$(CONFIG_ARCH_LPC32XX) += ea3250.dtb phy3250.dtb
index f6a3ffec1f4bbaa28eb742a1e47582a6dcdbe802..f48c2e961b84d0abe335167882455c928c4340f7 100644 (file)
@@ -607,6 +607,19 @@ static struct clk clk_dma = {
        .get_rate       = local_return_parent_rate,
 };
 
+static struct clk clk_pwm = {
+       .parent         = &clk_pclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_PWM_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_PWMCLK_PWM1CLK_EN |
+                         LPC32XX_CLKPWR_PWMCLK_PWM1SEL_PCLK |
+                         LPC32XX_CLKPWR_PWMCLK_PWM1_DIV(1) |
+                         LPC32XX_CLKPWR_PWMCLK_PWM2CLK_EN |
+                         LPC32XX_CLKPWR_PWMCLK_PWM2SEL_PCLK |
+                         LPC32XX_CLKPWR_PWMCLK_PWM2_DIV(1),
+       .get_rate       = local_return_parent_rate,
+};
+
 static struct clk clk_uart3 = {
        .parent         = &clk_pclk,
        .enable         = local_onoff_enable,
@@ -691,10 +704,21 @@ static struct clk clk_nand = {
        .parent         = &clk_hclk,
        .enable         = local_onoff_enable,
        .enable_reg     = LPC32XX_CLKPWR_NAND_CLK_CTRL,
-       .enable_mask    = LPC32XX_CLKPWR_NANDCLK_SLCCLK_EN,
+       .enable_mask    = LPC32XX_CLKPWR_NANDCLK_SLCCLK_EN |
+                         LPC32XX_CLKPWR_NANDCLK_SEL_SLC,
        .get_rate       = local_return_parent_rate,
 };
 
+static struct clk clk_nand_mlc = {
+       .parent         = &clk_hclk,
+       .enable         = local_onoff_enable,
+       .enable_reg     = LPC32XX_CLKPWR_NAND_CLK_CTRL,
+       .enable_mask    = LPC32XX_CLKPWR_NANDCLK_MLCCLK_EN |
+                         LPC32XX_CLKPWR_NANDCLK_DMA_INT |
+                         LPC32XX_CLKPWR_NANDCLK_INTSEL_MLC,
+       .get_rate       = local_return_parent_rate,
+};
+
 static struct clk clk_i2s0 = {
        .parent         = &clk_hclk,
        .enable         = local_onoff_enable,
@@ -707,7 +731,8 @@ static struct clk clk_i2s1 = {
        .parent         = &clk_hclk,
        .enable         = local_onoff_enable,
        .enable_reg     = LPC32XX_CLKPWR_I2S_CLK_CTRL,
-       .enable_mask    = LPC32XX_CLKPWR_I2SCTRL_I2SCLK1_EN,
+       .enable_mask    = LPC32XX_CLKPWR_I2SCTRL_I2SCLK1_EN |
+                         LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA,
        .get_rate       = local_return_parent_rate,
 };
 
@@ -727,14 +752,77 @@ static struct clk clk_rtc = {
        .get_rate       = local_return_parent_rate,
 };
 
+static int local_usb_enable(struct clk *clk, int enable)
+{
+       u32 tmp;
+
+       if (enable) {
+               /* Set up I2C pull levels */
+               tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL);
+               tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE;
+               __raw_writel(tmp, LPC32XX_CLKPWR_I2C_CLK_CTRL);
+       }
+
+       return local_onoff_enable(clk, enable);
+}
+
 static struct clk clk_usbd = {
        .parent         = &clk_usbpll,
-       .enable         = local_onoff_enable,
+       .enable         = local_usb_enable,
        .enable_reg     = LPC32XX_CLKPWR_USB_CTRL,
        .enable_mask    = LPC32XX_CLKPWR_USBCTRL_HCLK_EN,
        .get_rate       = local_return_parent_rate,
 };
 
+#define OTG_ALWAYS_MASK                (LPC32XX_USB_OTG_OTG_CLOCK_ON | \
+                                LPC32XX_USB_OTG_I2C_CLOCK_ON)
+
+static int local_usb_otg_enable(struct clk *clk, int enable)
+{
+       int to = 1000;
+
+       if (enable) {
+               __raw_writel(clk->enable_mask, clk->enable_reg);
+
+               while (((__raw_readl(LPC32XX_USB_OTG_CLK_STAT) &
+                       clk->enable_mask) != clk->enable_mask) && (to > 0))
+                       to--;
+       } else {
+               __raw_writel(OTG_ALWAYS_MASK, clk->enable_reg);
+
+               while (((__raw_readl(LPC32XX_USB_OTG_CLK_STAT) &
+                       OTG_ALWAYS_MASK) != OTG_ALWAYS_MASK) && (to > 0))
+                       to--;
+       }
+
+       if (to)
+               return 0;
+       else
+               return -1;
+}
+
+static struct clk clk_usb_otg_dev = {
+       .parent         = &clk_usbpll,
+       .enable         = local_usb_otg_enable,
+       .enable_reg     = LPC32XX_USB_OTG_CLK_CTRL,
+       .enable_mask    = LPC32XX_USB_OTG_AHB_M_CLOCK_ON |
+                         LPC32XX_USB_OTG_OTG_CLOCK_ON |
+                         LPC32XX_USB_OTG_DEV_CLOCK_ON |
+                         LPC32XX_USB_OTG_I2C_CLOCK_ON,
+       .get_rate       = local_return_parent_rate,
+};
+
+static struct clk clk_usb_otg_host = {
+       .parent         = &clk_usbpll,
+       .enable         = local_usb_otg_enable,
+       .enable_reg     = LPC32XX_USB_OTG_CLK_CTRL,
+       .enable_mask    = LPC32XX_USB_OTG_AHB_M_CLOCK_ON |
+                         LPC32XX_USB_OTG_OTG_CLOCK_ON |
+                         LPC32XX_USB_OTG_HOST_CLOCK_ON |
+                         LPC32XX_USB_OTG_I2C_CLOCK_ON,
+       .get_rate       = local_return_parent_rate,
+};
+
 static int tsc_onoff_enable(struct clk *clk, int enable)
 {
        u32 tmp;
@@ -800,11 +888,17 @@ static int mmc_onoff_enable(struct clk *clk, int enable)
        u32 tmp;
 
        tmp = __raw_readl(LPC32XX_CLKPWR_MS_CTRL) &
-               ~LPC32XX_CLKPWR_MSCARD_SDCARD_EN;
+               ~(LPC32XX_CLKPWR_MSCARD_SDCARD_EN |
+                 LPC32XX_CLKPWR_MSCARD_MSDIO_PU_EN |
+                 LPC32XX_CLKPWR_MSCARD_MSDIO_PIN_DIS |
+                 LPC32XX_CLKPWR_MSCARD_MSDIO0_DIS |
+                 LPC32XX_CLKPWR_MSCARD_MSDIO1_DIS |
+                 LPC32XX_CLKPWR_MSCARD_MSDIO23_DIS);
 
        /* If rate is 0, disable clock */
        if (enable != 0)
-               tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_EN;
+               tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_EN |
+                       LPC32XX_CLKPWR_MSCARD_MSDIO_PU_EN;
 
        __raw_writel(tmp, LPC32XX_CLKPWR_MS_CTRL);
 
@@ -853,7 +947,7 @@ static unsigned long mmc_round_rate(struct clk *clk, unsigned long rate)
 
 static int mmc_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 oldclk, tmp;
+       u32 tmp;
        unsigned long prate, div, crate = mmc_round_rate(clk, rate);
 
        prate = clk->parent->get_rate(clk->parent);
@@ -861,16 +955,12 @@ static int mmc_set_rate(struct clk *clk, unsigned long rate)
        div = prate / crate;
 
        /* The MMC clock must be on when accessing an MMC register */
-       oldclk = __raw_readl(LPC32XX_CLKPWR_MS_CTRL);
-       __raw_writel(oldclk | LPC32XX_CLKPWR_MSCARD_SDCARD_EN,
-               LPC32XX_CLKPWR_MS_CTRL);
        tmp = __raw_readl(LPC32XX_CLKPWR_MS_CTRL) &
                ~LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(0xf);
-       tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(div);
+       tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(div) |
+               LPC32XX_CLKPWR_MSCARD_SDCARD_EN;
        __raw_writel(tmp, LPC32XX_CLKPWR_MS_CTRL);
 
-       __raw_writel(oldclk, LPC32XX_CLKPWR_MS_CTRL);
-
        return 0;
 }
 
@@ -1111,6 +1201,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_INIT(NULL, "vfp9_ck", &clk_vfp9),
        CLKDEV_INIT("pl08xdmac", NULL, &clk_dma),
        CLKDEV_INIT("4003c000.watchdog", NULL, &clk_wdt),
+       CLKDEV_INIT("4005c000.pwm", NULL, &clk_pwm),
        CLKDEV_INIT(NULL, "uart3_ck", &clk_uart3),
        CLKDEV_INIT(NULL, "uart4_ck", &clk_uart4),
        CLKDEV_INIT(NULL, "uart5_ck", &clk_uart5),
@@ -1120,8 +1211,9 @@ static struct clk_lookup lookups[] = {
        CLKDEV_INIT("31020300.i2c", NULL, &clk_i2c2),
        CLKDEV_INIT("dev:ssp0", NULL, &clk_ssp0),
        CLKDEV_INIT("dev:ssp1", NULL, &clk_ssp1),
-       CLKDEV_INIT("lpc32xx_keys.0", NULL, &clk_kscan),
-       CLKDEV_INIT("lpc32xx-nand.0", "nand_ck", &clk_nand),
+       CLKDEV_INIT("40050000.key", NULL, &clk_kscan),
+       CLKDEV_INIT("20020000.flash", NULL, &clk_nand),
+       CLKDEV_INIT("200a8000.flash", NULL, &clk_nand_mlc),
        CLKDEV_INIT("40048000.adc", NULL, &clk_adc),
        CLKDEV_INIT(NULL, "i2s0_ck", &clk_i2s0),
        CLKDEV_INIT(NULL, "i2s1_ck", &clk_i2s1),
@@ -1130,6 +1222,9 @@ static struct clk_lookup lookups[] = {
        CLKDEV_INIT("31060000.ethernet", NULL, &clk_net),
        CLKDEV_INIT("dev:clcd", NULL, &clk_lcd),
        CLKDEV_INIT("31020000.usbd", "ck_usbd", &clk_usbd),
+       CLKDEV_INIT("31020000.ohci", "ck_usbd", &clk_usbd),
+       CLKDEV_INIT("31020000.usbd", "ck_usb_otg", &clk_usb_otg_dev),
+       CLKDEV_INIT("31020000.ohci", "ck_usb_otg", &clk_usb_otg_host),
        CLKDEV_INIT("lpc32xx_rtc", NULL, &clk_rtc),
 };
 
index 5c96057b6d78e2a864863a87e38e91a03086a62d..a48dc2dec4859a43be83a93d482469e19d8ced5d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/io.h>
 
 #include <asm/mach/map.h>
+#include <asm/system_info.h>
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
@@ -224,7 +225,7 @@ void lpc23xx_restart(char mode, const char *cmd)
                ;
 }
 
-static int __init lpc32xx_display_uid(void)
+static int __init lpc32xx_check_uid(void)
 {
        u32 uid[4];
 
@@ -233,6 +234,11 @@ static int __init lpc32xx_display_uid(void)
        printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
                uid[3], uid[2], uid[1], uid[0]);
 
+       if (!system_serial_low && !system_serial_high) {
+               system_serial_low = uid[0];
+               system_serial_high = uid[1];
+       }
+
        return 1;
 }
-arch_initcall(lpc32xx_display_uid);
+arch_initcall(lpc32xx_check_uid);
index 2ba6ca412bef3e06245853dfdeb5904ae54e3fbd..0052e7a761798acd1fef17aa5cf2a68ed8b43d29 100644 (file)
@@ -3,6 +3,4 @@
 
 #include "gpio-lpc32xx.h"
 
-#define ARCH_NR_GPIOS (LPC32XX_GPO_P3_GRP + LPC32XX_GPO_P3_MAX)
-
 #endif /* __MACH_GPIO_H */
index c584f5bb164fe5d8cedf6bb9cc3d05767c8faac3..acc4aabf1c7b090eae3cd64fc6a176aabbbf9542 100644 (file)
 #define LPC32XX_GPIO_P2_MUX_CLR                        _GPREG(0x02C)
 #define LPC32XX_GPIO_P2_MUX_STATE              _GPREG(0x030)
 
+/*
+ * USB Otg Registers
+ */
+#define _OTGREG(x)                     io_p2v(LPC32XX_USB_OTG_BASE + (x))
+#define LPC32XX_USB_OTG_CLK_CTRL       _OTGREG(0xFF4)
+#define LPC32XX_USB_OTG_CLK_STAT       _OTGREG(0xFF8)
+
+/* USB OTG CLK CTRL bit defines */
+#define LPC32XX_USB_OTG_AHB_M_CLOCK_ON _BIT(4)
+#define LPC32XX_USB_OTG_OTG_CLOCK_ON   _BIT(3)
+#define LPC32XX_USB_OTG_I2C_CLOCK_ON   _BIT(2)
+#define LPC32XX_USB_OTG_DEV_CLOCK_ON   _BIT(1)
+#define LPC32XX_USB_OTG_HOST_CLOCK_ON  _BIT(0)
+
 #endif
index 540106cdb9ec42658c404b92be618d8766570adf..b07dcc90829d7c3b2227bca72594d0381263ca1e 100644 (file)
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
 #include <linux/amba/pl022.h>
+#include <linux/amba/pl08x.h>
+#include <linux/amba/mmci.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
-#include <linux/amba/pl08x.h>
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -50,9 +51,9 @@
 /*
  * Mapped GPIOLIB GPIOs
  */
-#define SPI0_CS_GPIO   LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
-#define LCD_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0)
-#define BKL_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4)
+#define LCD_POWER_GPIO         LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0)
+#define BKL_POWER_GPIO         LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4)
+#define MMC_PWR_ENABLE_GPIO    LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 5)
 
 /*
  * AMBA LCD controller
@@ -158,24 +159,6 @@ static struct clcd_board lpc32xx_clcd_data = {
 /*
  * AMBA SSP (SPI)
  */
-static void phy3250_spi_cs_set(u32 control)
-{
-       gpio_set_value(SPI0_CS_GPIO, (int) control);
-}
-
-static struct pl022_config_chip spi0_chip_info = {
-       .com_mode               = INTERRUPT_TRANSFER,
-       .iface                  = SSP_INTERFACE_MOTOROLA_SPI,
-       .hierarchy              = SSP_MASTER,
-       .slave_tx_disable       = 0,
-       .rx_lev_trig            = SSP_RX_4_OR_MORE_ELEM,
-       .tx_lev_trig            = SSP_TX_4_OR_MORE_EMPTY_LOC,
-       .ctrl_len               = SSP_BITS_8,
-       .wait_state             = SSP_MWIRE_WAIT_ZERO,
-       .duplex                 = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
-       .cs_control             = phy3250_spi_cs_set,
-};
-
 static struct pl022_ssp_controller lpc32xx_ssp0_data = {
        .bus_id                 = 0,
        .num_chipselect         = 1,
@@ -188,45 +171,56 @@ static struct pl022_ssp_controller lpc32xx_ssp1_data = {
        .enable_dma             = 0,
 };
 
-/* AT25 driver registration */
-static int __init phy3250_spi_board_register(void)
+static struct pl08x_channel_data pl08x_slave_channels[] = {
+       {
+               .bus_id = "nand-slc",
+               .min_signal = 1, /* SLC NAND Flash */
+               .max_signal = 1,
+               .periph_buses = PL08X_AHB1,
+       },
+       {
+               .bus_id = "nand-mlc",
+               .min_signal = 12, /* MLC NAND Flash */
+               .max_signal = 12,
+               .periph_buses = PL08X_AHB1,
+       },
+};
+
+static int pl08x_get_signal(const struct pl08x_channel_data *cd)
+{
+       return cd->min_signal;
+}
+
+static void pl08x_put_signal(const struct pl08x_channel_data *cd, int ch)
 {
-#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
-       static struct spi_board_info info[] = {
-               {
-                       .modalias = "spidev",
-                       .max_speed_hz = 5000000,
-                       .bus_num = 0,
-                       .chip_select = 0,
-                       .controller_data = &spi0_chip_info,
-               },
-       };
-
-#else
-       static struct spi_eeprom eeprom = {
-               .name = "at25256a",
-               .byte_len = 0x8000,
-               .page_size = 64,
-               .flags = EE_ADDR2,
-       };
-
-       static struct spi_board_info info[] = {
-               {
-                       .modalias = "at25",
-                       .max_speed_hz = 5000000,
-                       .bus_num = 0,
-                       .chip_select = 0,
-                       .mode = SPI_MODE_0,
-                       .platform_data = &eeprom,
-                       .controller_data = &spi0_chip_info,
-               },
-       };
-#endif
-       return spi_register_board_info(info, ARRAY_SIZE(info));
 }
-arch_initcall(phy3250_spi_board_register);
 
 static struct pl08x_platform_data pl08x_pd = {
+       .slave_channels = &pl08x_slave_channels[0],
+       .num_slave_channels = ARRAY_SIZE(pl08x_slave_channels),
+       .get_signal = pl08x_get_signal,
+       .put_signal = pl08x_put_signal,
+       .lli_buses = PL08X_AHB1,
+       .mem_buses = PL08X_AHB1,
+};
+
+static int mmc_handle_ios(struct device *dev, struct mmc_ios *ios)
+{
+       /* Only on and off are supported */
+       if (ios->power_mode == MMC_POWER_OFF)
+               gpio_set_value(MMC_PWR_ENABLE_GPIO, 0);
+       else
+               gpio_set_value(MMC_PWR_ENABLE_GPIO, 1);
+       return 0;
+}
+
+static struct mmci_platform_data lpc32xx_mmci_data = {
+       .ocr_mask       = MMC_VDD_30_31 | MMC_VDD_31_32 |
+                         MMC_VDD_32_33 | MMC_VDD_33_34,
+       .ios_handler    = mmc_handle_ios,
+       .dma_filter     = NULL,
+       /* No DMA for now since AMBA PL080 dmaengine driver only does scatter
+        * gather, and the MMCI driver doesn't do it this way */
 };
 
 static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
@@ -234,6 +228,8 @@ static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
        OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", &lpc32xx_ssp1_data),
        OF_DEV_AUXDATA("arm,pl110", 0x31040000, "dev:clcd", &lpc32xx_clcd_data),
        OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd),
+       OF_DEV_AUXDATA("arm,pl18x", 0x20098000, "20098000.sd",
+                      &lpc32xx_mmci_data),
        { }
 };
 
@@ -241,10 +237,6 @@ static void __init lpc3250_machine_init(void)
 {
        u32 tmp;
 
-       /* Setup SLC NAND controller muxing */
-       __raw_writel(LPC32XX_CLKPWR_NANDCLK_SEL_SLC,
-               LPC32XX_CLKPWR_NAND_CLK_CTRL);
-
        /* Setup LCD muxing to RGB565 */
        tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL) &
                ~(LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK |
@@ -252,47 +244,8 @@ static void __init lpc3250_machine_init(void)
        tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16;
        __raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL);
 
-       /* Set up USB power */
-       tmp = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
-       tmp |= LPC32XX_CLKPWR_USBCTRL_HCLK_EN |
-               LPC32XX_CLKPWR_USBCTRL_USBI2C_EN;
-       __raw_writel(tmp, LPC32XX_CLKPWR_USB_CTRL);
-
-       /* Set up I2C pull levels */
-       tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL);
-       tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE |
-               LPC32XX_CLKPWR_I2CCLK_I2C2HI_DRIVE;
-       __raw_writel(tmp, LPC32XX_CLKPWR_I2C_CLK_CTRL);
-
-       /* Disable IrDA pulsing support on UART6 */
-       tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
-       tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
-       __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
-
-       /* Enable DMA for I2S1 channel */
-       tmp = __raw_readl(LPC32XX_CLKPWR_I2S_CLK_CTRL);
-       tmp = LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA;
-       __raw_writel(tmp, LPC32XX_CLKPWR_I2S_CLK_CTRL);
-
        lpc32xx_serial_init();
 
-       /*
-        * AMBA peripheral clocks need to be enabled prior to AMBA device
-        * detection or a data fault will occur, so enable the clocks
-        * here.
-        */
-       tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
-       __raw_writel((tmp | LPC32XX_CLKPWR_LCDCTRL_CLK_EN),
-               LPC32XX_CLKPWR_LCDCLK_CTRL);
-
-       tmp = __raw_readl(LPC32XX_CLKPWR_SSP_CLK_CTRL);
-       __raw_writel((tmp | LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN),
-               LPC32XX_CLKPWR_SSP_CLK_CTRL);
-
-       tmp = __raw_readl(LPC32XX_CLKPWR_DMA_CLK_CTRL);
-       __raw_writel((tmp | LPC32XX_CLKPWR_DMACLKCTRL_CLK_EN),
-                    LPC32XX_CLKPWR_DMA_CLK_CTRL);
-
        /* Test clock needed for UDA1380 initial init */
        __raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC |
                LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN,
@@ -302,12 +255,10 @@ static void __init lpc3250_machine_init(void)
                             lpc32xx_auxdata_lookup, NULL);
 
        /* Register GPIOs used on this board */
-       if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
-               printk(KERN_ERR "Error requesting gpio %u",
-                       SPI0_CS_GPIO);
-       else if (gpio_direction_output(SPI0_CS_GPIO, 1))
-               printk(KERN_ERR "Error setting gpio %u to output",
-                       SPI0_CS_GPIO);
+       if (gpio_request(MMC_PWR_ENABLE_GPIO, "mmc_power_en"))
+               pr_err("Error requesting gpio %u", MMC_PWR_ENABLE_GPIO);
+       else if (gpio_direction_output(MMC_PWR_ENABLE_GPIO, 1))
+               pr_err("Error setting gpio %u to output", MMC_PWR_ENABLE_GPIO);
 }
 
 static char const *lpc32xx_dt_compat[] __initdata = {
index f2735281616a1d8a9e008c09d7483fa637a314cf..05621a29fba22cb5a1754f525d90817c9eaf3c57 100644 (file)
 
 #define LPC32XX_SUART_FIFO_SIZE        64
 
-/* Standard 8250/16550 compatible serial ports */
-static struct plat_serial8250_port serial_std_platform_data[] = {
-#ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT
-       {
-               .membase        = io_p2v(LPC32XX_UART5_BASE),
-               .mapbase        = LPC32XX_UART5_BASE,
-               .irq            = IRQ_LPC32XX_UART_IIR5,
-               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
-               .regshift       = 2,
-               .iotype         = UPIO_MEM32,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
-                                       UPF_SKIP_TEST,
-       },
-#endif
-#ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
-       {
-               .membase        = io_p2v(LPC32XX_UART3_BASE),
-               .mapbase        = LPC32XX_UART3_BASE,
-               .irq            = IRQ_LPC32XX_UART_IIR3,
-               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
-               .regshift       = 2,
-               .iotype         = UPIO_MEM32,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
-                                       UPF_SKIP_TEST,
-       },
-#endif
-#ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
-       {
-               .membase        = io_p2v(LPC32XX_UART4_BASE),
-               .mapbase        = LPC32XX_UART4_BASE,
-               .irq            = IRQ_LPC32XX_UART_IIR4,
-               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
-               .regshift       = 2,
-               .iotype         = UPIO_MEM32,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
-                                       UPF_SKIP_TEST,
-       },
-#endif
-#ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
-       {
-               .membase        = io_p2v(LPC32XX_UART6_BASE),
-               .mapbase        = LPC32XX_UART6_BASE,
-               .irq            = IRQ_LPC32XX_UART_IIR6,
-               .uartclk        = LPC32XX_MAIN_OSC_FREQ,
-               .regshift       = 2,
-               .iotype         = UPIO_MEM32,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
-                                       UPF_SKIP_TEST,
-       },
-#endif
-       { },
-};
-
 struct uartinit {
        char *uart_ck_name;
        u32 ck_mode_mask;
@@ -92,7 +39,6 @@ struct uartinit {
 };
 
 static struct uartinit uartinit_data[] __initdata = {
-#ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT
        {
                .uart_ck_name = "uart5_ck",
                .ck_mode_mask =
@@ -100,8 +46,6 @@ static struct uartinit uartinit_data[] __initdata = {
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
                .mapbase = LPC32XX_UART5_BASE,
        },
-#endif
-#ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
        {
                .uart_ck_name = "uart3_ck",
                .ck_mode_mask =
@@ -109,8 +53,6 @@ static struct uartinit uartinit_data[] __initdata = {
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
                .mapbase = LPC32XX_UART3_BASE,
        },
-#endif
-#ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
        {
                .uart_ck_name = "uart4_ck",
                .ck_mode_mask =
@@ -118,8 +60,6 @@ static struct uartinit uartinit_data[] __initdata = {
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
                .mapbase = LPC32XX_UART4_BASE,
        },
-#endif
-#ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
        {
                .uart_ck_name = "uart6_ck",
                .ck_mode_mask =
@@ -127,19 +67,6 @@ static struct uartinit uartinit_data[] __initdata = {
                .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
                .mapbase = LPC32XX_UART6_BASE,
        },
-#endif
-};
-
-static struct platform_device serial_std_platform_device = {
-       .name                   = "serial8250",
-       .id                     = 0,
-       .dev                    = {
-               .platform_data  = serial_std_platform_data,
-       },
-};
-
-static struct platform_device *lpc32xx_serial_devs[] __initdata = {
-       &serial_std_platform_device,
 };
 
 void __init lpc32xx_serial_init(void)
@@ -156,15 +83,8 @@ void __init lpc32xx_serial_init(void)
                clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
                if (!IS_ERR(clk)) {
                        clk_enable(clk);
-                       serial_std_platform_data[i].uartclk =
-                               clk_get_rate(clk);
                }
 
-               /* Fall back on main osc rate if clock rate return fails */
-               if (serial_std_platform_data[i].uartclk == 0)
-                       serial_std_platform_data[i].uartclk =
-                               LPC32XX_MAIN_OSC_FREQ;
-
                /* Setup UART clock modes for all UARTs, disable autoclock */
                clkmodes |= uartinit_data[i].ck_mode_mask;
 
@@ -189,7 +109,7 @@ void __init lpc32xx_serial_init(void)
        __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
        for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
                /* Force a flush of the RX FIFOs to work around a HW bug */
-               puart = serial_std_platform_data[i].mapbase;
+               puart = uartinit_data[i].mapbase;
                __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
                __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
                j = LPC32XX_SUART_FIFO_SIZE;
@@ -198,11 +118,13 @@ void __init lpc32xx_serial_init(void)
                __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
        }
 
+       /* Disable IrDA pulsing support on UART6 */
+       tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
+       tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
+       __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
+
        /* Disable UART5->USB transparent mode or USB won't work */
        tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
        tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB;
        __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
-
-       platform_add_devices(lpc32xx_serial_devs,
-               ARRAY_SIZE(lpc32xx_serial_devs));
 }
diff --git a/arch/arm/mach-mmp/include/mach/gpio-pxa.h b/arch/arm/mach-mmp/include/mach/gpio-pxa.h
deleted file mode 100644 (file)
index 0e135a5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __ASM_MACH_GPIO_PXA_H
-#define __ASM_MACH_GPIO_PXA_H
-
-#include <mach/addr-map.h>
-#include <mach/cputype.h>
-#include <mach/irqs.h>
-
-#define GPIO_REGS_VIRT (APB_VIRT_BASE + 0x19000)
-
-#define BANK_OFF(n)    (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
-#define GPIO_REG(x)    (*(volatile u32 *)(GPIO_REGS_VIRT + (x)))
-
-#define gpio_to_bank(gpio)     ((gpio) >> 5)
-
-/* NOTE: these macros are defined here to make optimization of
- * gpio_{get,set}_value() to work when 'gpio' is a constant.
- * Usage of these macros otherwise is no longer recommended,
- * use generic GPIO API whenever possible.
- */
-#define GPIO_bit(gpio) (1 << ((gpio) & 0x1f))
-
-#define GPLR(x)                GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x00)
-#define GPDR(x)                GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x0c)
-#define GPSR(x)                GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x18)
-#define GPCR(x)                GPIO_REG(BANK_OFF(gpio_to_bank(x)) + 0x24)
-
-#include <plat/gpio-pxa.h>
-
-#endif /* __ASM_MACH_GPIO_PXA_H */
index c64dbb96dbad53a4264b8559ec531f229b75d08b..eb187e0e059bdbb1459b2ae21d69b6050176cba2 100644 (file)
@@ -31,5 +31,6 @@
 #define IRQ_MASK_HIGH_OFF      0x0014
 
 #define TIMER_VIRT_BASE                (BRIDGE_VIRT_BASE | 0x0300)
+#define TIMER_PHYS_BASE                (BRIDGE_PHYS_BASE | 0x0300)
 
 #endif
index 3674497162e3efa3b2238360fda132e9761a4d21..e807c4c52a0b6331a4e02146f71edc127d95cb7f 100644 (file)
@@ -42,6 +42,7 @@
 #define MV78XX0_CORE0_REGS_PHYS_BASE   0xf1020000
 #define MV78XX0_CORE1_REGS_PHYS_BASE   0xf1024000
 #define MV78XX0_CORE_REGS_VIRT_BASE    0xfe400000
+#define MV78XX0_CORE_REGS_PHYS_BASE    0xfe400000
 #define MV78XX0_CORE_REGS_SIZE         SZ_16K
 
 #define MV78XX0_PCIE_IO_PHYS_BASE(i)   (0xf0800000 + ((i) << 20))
@@ -59,6 +60,7 @@
  * Core-specific peripheral registers.
  */
 #define BRIDGE_VIRT_BASE       (MV78XX0_CORE_REGS_VIRT_BASE)
+#define BRIDGE_PHYS_BASE       (MV78XX0_CORE_REGS_PHYS_BASE)
 
 /*
  * Register Map
index 91cf0625819c2f62639cff7216e6563b9813e585..ccdf83b17cf16030612bdf62c43711f7f926baa6 100644 (file)
@@ -16,6 +16,7 @@ config SOC_IMX28
        bool
        select ARM_AMBA
        select CPU_ARM926T
+       select HAVE_CAN_FLEXCAN if CAN
        select HAVE_PWM
        select PINCTRL_IMX28
 
index 07b11fe6453f525bc43fc15cf32694388188f0c7..4582999cf0805ec1b79ce888a224d8669695f562 100644 (file)
@@ -1 +1,10 @@
 zreladdr-y += 0x40008000
+
+dtb-y += imx23-evk.dtb \
+        imx23-olinuxino.dtb \
+        imx23-stmp378x_devb.dtb \
+        imx28-apx4devkit.dtb \
+        imx28-cfa10036.dtb \
+        imx28-evk.dtb \
+        imx28-m28evk.dtb \
+        imx28-tx28.dtb \
index 9acdd6387047dd89663b90ab1cb80cca3245260d..9ee5cede3d42f5d646cac069888ebb563aefe163 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include <mach/mx23.h>
 #include <mach/devices-common.h>
-#include <mach/mxsfb.h>
+#include <linux/mxsfb.h>
 #include <linux/amba/bus.h>
 
 static inline int mx23_add_duart(void)
index 84b2960df117f56920a481253b6596ad1eb37356..fcab431060f486e7da61eaa07f2d46f62a31e0b6 100644 (file)
@@ -10,7 +10,7 @@
  */
 #include <mach/mx28.h>
 #include <mach/devices-common.h>
-#include <mach/mxsfb.h>
+#include <linux/mxsfb.h>
 #include <linux/amba/bus.h>
 
 static inline int mx28_add_duart(void)
index 5a75b7180f74b616939b30c0aeeaa7c3f987f847..76b53f73418e695a6b0826e8ea8b4f03d8b78910 100644 (file)
@@ -10,7 +10,7 @@
 #include <mach/mx23.h>
 #include <mach/mx28.h>
 #include <mach/devices-common.h>
-#include <mach/mxsfb.h>
+#include <linux/mxsfb.h>
 
 #ifdef CONFIG_SOC_IMX23
 struct platform_device *__init mx23_add_mxsfb(
index 5e90b9dcdef8789e10d71d2a8500604d53e57eeb..f5f061757deb54371e599730d8f38fc0b15c100e 100644 (file)
@@ -205,6 +205,16 @@ static int apx4devkit_phy_fixup(struct phy_device *phy)
        return 0;
 }
 
+static void __init apx4devkit_fec_phy_clk_enable(void)
+{
+       struct clk *clk;
+
+       /* Enable fec phy clock */
+       clk = clk_get_sys("enet_out", NULL);
+       if (!IS_ERR(clk))
+               clk_prepare_enable(clk);
+}
+
 static void __init apx4devkit_init(void)
 {
        mx28_soc_init();
@@ -225,6 +235,7 @@ static void __init apx4devkit_init(void)
        phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
                        apx4devkit_phy_fixup);
 
+       apx4devkit_fec_phy_clk_enable();
        mx28_add_fec(0, &mx28_fec_pdata);
 
        mx28_add_mxs_mmc(0, &apx4devkit_mmc_pdata);
index 8cac94b33020c64fb1a3f2efc80a3af5b5fbba21..648bdd05d38bb95006401378af9540580501970a 100644 (file)
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/irqdomain.h>
+#include <linux/micrel_phy.h>
+#include <linux/mxsfb.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/phy.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/common.h>
 
+static struct fb_videomode mx23evk_video_modes[] = {
+       {
+               .name           = "Samsung-LMS430HF02",
+               .refresh        = 60,
+               .xres           = 480,
+               .yres           = 272,
+               .pixclock       = 108096, /* picosecond (9.2 MHz) */
+               .left_margin    = 15,
+               .right_margin   = 8,
+               .upper_margin   = 12,
+               .lower_margin   = 4,
+               .hsync_len      = 1,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_DATA_ENABLE_HIGH_ACT |
+                                 FB_SYNC_DOTCLK_FAILING_ACT,
+       },
+};
+
+static struct fb_videomode mx28evk_video_modes[] = {
+       {
+               .name           = "Seiko-43WVF1G",
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = 29851, /* picosecond (33.5 MHz) */
+               .left_margin    = 89,
+               .right_margin   = 164,
+               .upper_margin   = 23,
+               .lower_margin   = 10,
+               .hsync_len      = 10,
+               .vsync_len      = 10,
+               .sync           = FB_SYNC_DATA_ENABLE_HIGH_ACT |
+                                 FB_SYNC_DOTCLK_FAILING_ACT,
+       },
+};
+
+static struct fb_videomode m28evk_video_modes[] = {
+       {
+               .name           = "Ampire AM-800480R2TMQW-T01H",
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = 30066, /* picosecond (33.26 MHz) */
+               .left_margin    = 0,
+               .right_margin   = 256,
+               .upper_margin   = 0,
+               .lower_margin   = 45,
+               .hsync_len      = 1,
+               .vsync_len      = 1,
+               .sync           = FB_SYNC_DATA_ENABLE_HIGH_ACT,
+       },
+};
+
+static struct fb_videomode apx4devkit_video_modes[] = {
+       {
+               .name           = "HannStar PJ70112A",
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = 33333, /* picosecond (30.00 MHz) */
+               .left_margin    = 88,
+               .right_margin   = 40,
+               .upper_margin   = 32,
+               .lower_margin   = 13,
+               .hsync_len      = 48,
+               .vsync_len      = 3,
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT |
+                                 FB_SYNC_DATA_ENABLE_HIGH_ACT |
+                                 FB_SYNC_DOTCLK_FAILING_ACT,
+       },
+};
+
+static struct mxsfb_platform_data mxsfb_pdata __initdata;
+
+static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
+       OF_DEV_AUXDATA("fsl,imx23-lcdif", 0x80030000, NULL, &mxsfb_pdata),
+       OF_DEV_AUXDATA("fsl,imx28-lcdif", 0x80030000, NULL, &mxsfb_pdata),
+       { /* sentinel */ }
+};
+
 static int __init mxs_icoll_add_irq_domain(struct device_node *np,
                                struct device_node *interrupt_parent)
 {
@@ -71,33 +154,155 @@ static struct sys_timer imx28_timer = {
        .init = imx28_timer_init,
 };
 
-static void __init imx28_evk_init(void)
+enum mac_oui {
+       OUI_FSL,
+       OUI_DENX,
+};
+
+static void __init update_fec_mac_prop(enum mac_oui oui)
+{
+       struct device_node *np, *from = NULL;
+       struct property *oldmac, *newmac;
+       const u32 *ocotp = mxs_get_ocotp();
+       u8 *macaddr;
+       u32 val;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               np = of_find_compatible_node(from, NULL, "fsl,imx28-fec");
+               if (!np)
+                       return;
+               from = np;
+
+               newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
+               if (!newmac)
+                       return;
+               newmac->value = newmac + 1;
+               newmac->length = 6;
+
+               newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
+               if (!newmac->name) {
+                       kfree(newmac);
+                       return;
+               }
+
+               /*
+                * OCOTP only stores the last 4 octets for each mac address,
+                * so hard-code OUI here.
+                */
+               macaddr = newmac->value;
+               switch (oui) {
+               case OUI_FSL:
+                       macaddr[0] = 0x00;
+                       macaddr[1] = 0x04;
+                       macaddr[2] = 0x9f;
+                       break;
+               case OUI_DENX:
+                       macaddr[0] = 0xc0;
+                       macaddr[1] = 0xe5;
+                       macaddr[2] = 0x4e;
+                       break;
+               }
+               val = ocotp[i];
+               macaddr[3] = (val >> 16) & 0xff;
+               macaddr[4] = (val >> 8) & 0xff;
+               macaddr[5] = (val >> 0) & 0xff;
+
+               oldmac = of_find_property(np, newmac->name, NULL);
+               if (oldmac)
+                       prom_update_property(np, newmac, oldmac);
+               else
+                       prom_add_property(np, newmac);
+       }
+}
+
+static void __init imx23_evk_init(void)
+{
+       mxsfb_pdata.mode_list = mx23evk_video_modes;
+       mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes);
+       mxsfb_pdata.default_bpp = 32;
+       mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
+}
+
+static inline void enable_clk_enet_out(void)
 {
-       struct clk *clk;
+       struct clk *clk = clk_get_sys("enet_out", NULL);
 
-       /* Enable fec phy clock */
-       clk = clk_get_sys("enet_out", NULL);
        if (!IS_ERR(clk))
                clk_prepare_enable(clk);
 }
 
+static void __init imx28_evk_init(void)
+{
+       enable_clk_enet_out();
+       update_fec_mac_prop(OUI_FSL);
+
+       mxsfb_pdata.mode_list = mx28evk_video_modes;
+       mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes);
+       mxsfb_pdata.default_bpp = 32;
+       mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
+}
+
+static void __init m28evk_init(void)
+{
+       enable_clk_enet_out();
+       update_fec_mac_prop(OUI_DENX);
+
+       mxsfb_pdata.mode_list = m28evk_video_modes;
+       mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes);
+       mxsfb_pdata.default_bpp = 16;
+       mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT;
+}
+
+static int apx4devkit_phy_fixup(struct phy_device *phy)
+{
+       phy->dev_flags |= MICREL_PHY_50MHZ_CLK;
+       return 0;
+}
+
+static void __init apx4devkit_init(void)
+{
+       enable_clk_enet_out();
+
+       if (IS_BUILTIN(CONFIG_PHYLIB))
+               phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
+                                          apx4devkit_phy_fixup);
+
+       mxsfb_pdata.mode_list = apx4devkit_video_modes;
+       mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes);
+       mxsfb_pdata.default_bpp = 32;
+       mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
+}
+
 static void __init mxs_machine_init(void)
 {
        if (of_machine_is_compatible("fsl,imx28-evk"))
                imx28_evk_init();
+       else if (of_machine_is_compatible("fsl,imx23-evk"))
+               imx23_evk_init();
+       else if (of_machine_is_compatible("denx,m28evk"))
+               m28evk_init();
+       else if (of_machine_is_compatible("bluegiga,apx4devkit"))
+               apx4devkit_init();
 
        of_platform_populate(NULL, of_default_bus_match_table,
-                               NULL, NULL);
+                            mxs_auxdata_lookup, NULL);
 }
 
 static const char *imx23_dt_compat[] __initdata = {
        "fsl,imx23-evk",
+       "fsl,stmp378x_devb"
+       "olimex,imx23-olinuxino",
        "fsl,imx23",
        NULL,
 };
 
 static const char *imx28_dt_compat[] __initdata = {
+       "bluegiga,apx4devkit",
+       "crystalfontz,cfa10036",
+       "denx,m28evk",
        "fsl,imx28-evk",
+       "karo,tx28",
        "fsl,imx28",
        NULL,
 };
index 9a7b08b2a92559caf1028df076040c5e5dc798ae..0f71f82101cc00bcf20e831d8e61dc780f276448 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/gpio.h>
 
 #include <mach/iomux-mx28.h>
-#include "../devices-mx28.h"
+#include "devices-mx28.h"
 
 #include "module-tx28.h"
 
index a6bbd1a7b4e7d1c4d053b462386afe5a432dffad..a42c9a33d3bf54472ae101ddef035e58ca873463 100644 (file)
@@ -7,8 +7,6 @@
 
 # Object file lists.
 
-obj-y                  += clock.o
-
 # Cpu revision
 obj-$(CONFIG_NOMADIK_8815) += cpu-8815.o
 
index 2e8d3e176bc70b7216b5b8aa818b648ae63ebee0..f4535a7dadf537d7ffc0a691598db24103ba4ab1 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/i2c.h>
 #include <linux/io.h>
 #include <asm/hardware/vic.h>
 #include <asm/sizes.h>
@@ -185,16 +187,28 @@ static void __init nhk8815_onenand_init(void)
 #endif
 }
 
-static AMBA_APB_DEVICE(uart0, "uart0", 0, NOMADIK_UART0_BASE,
-       { IRQ_UART0 }, NULL);
+static struct mmci_platform_data mmcsd_plat_data = {
+       .ocr_mask = MMC_VDD_29_30,
+       .f_max = 48000000,
+       .gpio_wp = -1,
+       .gpio_cd = 111,
+       .cd_invert = true,
+       .capabilities = MMC_CAP_MMC_HIGHSPEED |
+       MMC_CAP_SD_HIGHSPEED | MMC_CAP_4_BIT_DATA,
+};
 
-static AMBA_APB_DEVICE(uart1, "uart1", 0, NOMADIK_UART1_BASE,
-       { IRQ_UART1 }, NULL);
+static int __init nhk8815_mmcsd_init(void)
+{
+       int ret;
 
-static struct amba_device *amba_devs[] __initdata = {
-       &uart0_device,
-       &uart1_device,
-};
+       ret = gpio_request(112, "card detect bias");
+       if (ret)
+               return ret;
+       gpio_direction_output(112, 0);
+       amba_apb_device_add(NULL, "mmci", NOMADIK_SDI_BASE, SZ_4K, IRQ_SDMMC, 0, &mmcsd_plat_data, 0x10180180);
+       return 0;
+}
+module_init(nhk8815_mmcsd_init);
 
 static struct resource nhk8815_eth_resources[] = {
        {
@@ -253,17 +267,46 @@ static struct sys_timer nomadik_timer = {
        .init   = nomadik_timer_init,
 };
 
+static struct i2c_board_info __initdata nhk8815_i2c0_devices[] = {
+       {
+               I2C_BOARD_INFO("stw4811", 0x2d),
+       },
+};
+
+static struct i2c_board_info __initdata nhk8815_i2c1_devices[] = {
+       {
+               I2C_BOARD_INFO("camera", 0x10),
+       },
+       {
+               I2C_BOARD_INFO("stw5095", 0x1a),
+       },
+       {
+               I2C_BOARD_INFO("lis3lv02dl", 0x1d),
+       },
+};
+
+static struct i2c_board_info __initdata nhk8815_i2c2_devices[] = {
+       {
+               I2C_BOARD_INFO("stw4811-usb", 0x2d),
+       },
+};
+
 static void __init nhk8815_platform_init(void)
 {
-       int i;
-
        cpu8815_platform_init();
        nhk8815_onenand_init();
        platform_add_devices(nhk8815_platform_devices,
                             ARRAY_SIZE(nhk8815_platform_devices));
 
-       for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-               amba_device_register(amba_devs[i], &iomem_resource);
+       amba_apb_device_add(NULL, "uart0", NOMADIK_UART0_BASE, SZ_4K, IRQ_UART0, 0, NULL, 0);
+       amba_apb_device_add(NULL, "uart1", NOMADIK_UART1_BASE, SZ_4K, IRQ_UART1, 0, NULL, 0);
+
+       i2c_register_board_info(0, nhk8815_i2c0_devices,
+                               ARRAY_SIZE(nhk8815_i2c0_devices));
+       i2c_register_board_info(1, nhk8815_i2c1_devices,
+                               ARRAY_SIZE(nhk8815_i2c1_devices));
+       i2c_register_board_info(2, nhk8815_i2c2_devices,
+                               ARRAY_SIZE(nhk8815_i2c2_devices));
 }
 
 MACHINE_START(NOMADIK, "NHK8815")
diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c
deleted file mode 100644 (file)
index 48a59f2..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *  linux/arch/arm/mach-nomadik/clock.c
- *
- *  Copyright (C) 2009 Alessandro Rubini
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include "clock.h"
-
-/*
- * The nomadik board uses generic clocks, but the serial pl011 file
- * calls clk_enable(), clk_disable(), clk_get_rate(), so we provide them
- */
-unsigned long clk_get_rate(struct clk *clk)
-{
-       return clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-/* enable and disable do nothing */
-int clk_enable(struct clk *clk)
-{
-       return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_disable);
-
-static struct clk clk_24 = {
-       .rate = 2400000,
-};
-
-static struct clk clk_48 = {
-       .rate = 48 * 1000 * 1000,
-};
-
-/*
- * Catch-all default clock to satisfy drivers using the clk API.  We don't
- * model the actual hardware clocks yet.
- */
-static struct clk clk_default;
-
-#define CLK(_clk, dev)                         \
-       {                                       \
-               .clk            = _clk,         \
-               .dev_id         = dev,          \
-       }
-
-static struct clk_lookup lookups[] = {
-       {
-               .con_id         = "apb_pclk",
-               .clk            = &clk_default,
-       },
-       CLK(&clk_24, "mtu0"),
-       CLK(&clk_24, "mtu1"),
-       CLK(&clk_48, "uart0"),
-       CLK(&clk_48, "uart1"),
-       CLK(&clk_default, "gpio.0"),
-       CLK(&clk_default, "gpio.1"),
-       CLK(&clk_default, "gpio.2"),
-       CLK(&clk_default, "gpio.3"),
-       CLK(&clk_default, "rng"),
-};
-
-int __init clk_init(void)
-{
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-       return 0;
-}
diff --git a/arch/arm/mach-nomadik/clock.h b/arch/arm/mach-nomadik/clock.h
deleted file mode 100644 (file)
index 78da2e7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-
-/*
- *  linux/arch/arm/mach-nomadik/clock.h
- *
- *  Copyright (C) 2009 Alessandro Rubini
- *
- * 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.
- */
-struct clk {
-       unsigned long           rate;
-};
-
-int __init clk_init(void);
index 27f43a46985ee15c33551ab582bafb45f5783fdd..6fd8e46567a4e602fc15bed22f97f8661e7dc1c5 100644 (file)
 #include <linux/amba/bus.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/clk-nomadik.h>
 
 #include <plat/gpio-nomadik.h>
 #include <mach/hardware.h>
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 
-#include "clock.h"
 #include "cpu-8815.h"
 
-#define __MEM_4K_RESOURCE(x) \
-       .res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
-
 /* The 8815 has 4 GPIO blocks, let's register them immediately */
-
-#define GPIO_RESOURCE(block)                                           \
-       {                                                               \
-               .start  = NOMADIK_GPIO##block##_BASE,                   \
-               .end    = NOMADIK_GPIO##block##_BASE + SZ_4K - 1,       \
-               .flags  = IORESOURCE_MEM,                               \
-       },                                                              \
-       {                                                               \
-               .start  = IRQ_GPIO##block,                              \
-               .end    = IRQ_GPIO##block,                              \
-               .flags  = IORESOURCE_IRQ,                               \
-       }
-
-#define GPIO_DEVICE(block)                                             \
-       {                                                               \
-               .name           = "gpio",                               \
-               .id             = block,                                \
-               .num_resources  = 2,                                    \
-               .resource       = &cpu8815_gpio_resources[block * 2],   \
-               .dev = {                                                \
-                       .platform_data = &cpu8815_gpio[block],          \
-               },                                                      \
-       }
-
-static struct nmk_gpio_platform_data cpu8815_gpio[] = {
-       {
-               .name = "GPIO-0-31",
-               .first_gpio = 0,
-               .first_irq = NOMADIK_GPIO_TO_IRQ(0),
-       }, {
-               .name = "GPIO-32-63",
-               .first_gpio = 32,
-               .first_irq = NOMADIK_GPIO_TO_IRQ(32),
-       }, {
-               .name = "GPIO-64-95",
-               .first_gpio = 64,
-               .first_irq = NOMADIK_GPIO_TO_IRQ(64),
-       }, {
-               .name = "GPIO-96-127", /* 124..127 not routed to pin */
-               .first_gpio = 96,
-               .first_irq = NOMADIK_GPIO_TO_IRQ(96),
-       }
+static resource_size_t __initdata cpu8815_gpio_base[] = {
+       NOMADIK_GPIO0_BASE,
+       NOMADIK_GPIO1_BASE,
+       NOMADIK_GPIO2_BASE,
+       NOMADIK_GPIO3_BASE,
 };
 
-static struct resource cpu8815_gpio_resources[] = {
-       GPIO_RESOURCE(0),
-       GPIO_RESOURCE(1),
-       GPIO_RESOURCE(2),
-       GPIO_RESOURCE(3),
-};
-
-static struct platform_device cpu8815_platform_gpio[] = {
-       GPIO_DEVICE(0),
-       GPIO_DEVICE(1),
-       GPIO_DEVICE(2),
-       GPIO_DEVICE(3),
-};
+static struct platform_device *
+cpu8815_add_gpio(int id, resource_size_t addr, int irq,
+                struct nmk_gpio_platform_data *pdata)
+{
+       struct resource resources[] = {
+               {
+                       .start  = addr,
+                       .end    = addr + 127,
+                       .flags  = IORESOURCE_MEM,
+               },
+               {
+                       .start  = irq,
+                       .end    = irq,
+                       .flags  = IORESOURCE_IRQ,
+               }
+       };
+
+       return platform_device_register_resndata(NULL, "gpio", id,
+                               resources, ARRAY_SIZE(resources),
+                               pdata, sizeof(*pdata));
+}
 
-static AMBA_APB_DEVICE(cpu8815_amba_rng, "rng", 0, NOMADIK_RNG_BASE, { }, NULL);
+void cpu8815_add_gpios(resource_size_t *base, int num, int irq,
+                      struct nmk_gpio_platform_data *pdata)
+{
+       int first = 0;
+       int i;
 
-static struct platform_device *platform_devs[] __initdata = {
-       cpu8815_platform_gpio + 0,
-       cpu8815_platform_gpio + 1,
-       cpu8815_platform_gpio + 2,
-       cpu8815_platform_gpio + 3,
-};
+       for (i = 0; i < num; i++, first += 32, irq++) {
+               pdata->first_gpio = first;
+               pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
+               pdata->num_gpio = 32;
 
-static struct amba_device *amba_devs[] __initdata = {
-       &cpu8815_amba_rng_device
-};
+               cpu8815_add_gpio(i, base[i], irq, pdata);
+       }
+}
 
 static int __init cpu8815_init(void)
 {
-       int i;
-
-       platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
-       for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
-               amba_device_register(amba_devs[i], &iomem_resource);
+       struct nmk_gpio_platform_data pdata = {
+               /* No custom data yet */
+       };
+
+       cpu8815_add_gpios(cpu8815_gpio_base, ARRAY_SIZE(cpu8815_gpio_base),
+                         IRQ_GPIO0, &pdata);
+       amba_apb_device_add(NULL, "rng", NOMADIK_RNG_BASE, SZ_4K, 0, 0, NULL, 0);
+       amba_apb_device_add(NULL, "rtc-pl031", NOMADIK_RTC_BASE, SZ_4K, IRQ_RTC_RTT, 0, NULL, 0);
        return 0;
 }
 arch_initcall(cpu8815_init);
@@ -147,7 +123,7 @@ void __init cpu8815_init_irq(void)
         * Init clocks here so that they are available for system timer
         * initialization.
         */
-       clk_init();
+       nomadik_clk_init();
 }
 
 /*
index 0fc2f6f1cc979097cf83de13a924c7fb05a105f1..6d14454d46094fc4bdd00c66cabff3a0abb800f9 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/i2c-gpio.h>
 #include <linux/platform_device.h>
 #include <plat/gpio-nomadik.h>
+#include <plat/pincfg.h>
 
 /*
  * There are two busses in the 8815NHK.
  * use bit-bang through GPIO by now, to keep things simple
  */
 
+/* I2C0 connected to the STw4811 power management chip */
 static struct i2c_gpio_platform_data nhk8815_i2c_data0 = {
        /* keep defaults for timeouts; pins are push-pull bidirectional */
        .scl_pin = 62,
        .sda_pin = 63,
 };
 
+/* I2C1 connected to various sensors */
 static struct i2c_gpio_platform_data nhk8815_i2c_data1 = {
        /* keep defaults for timeouts; pins are push-pull bidirectional */
        .scl_pin = 53,
        .sda_pin = 54,
 };
 
-/* first bus: GPIO XX and YY */
+/* I2C2 connected to the USB portions of the STw4811 only */
+static struct i2c_gpio_platform_data nhk8815_i2c_data2 = {
+       /* keep defaults for timeouts; pins are push-pull bidirectional */
+       .scl_pin = 73,
+       .sda_pin = 74,
+};
+
 static struct platform_device nhk8815_i2c_dev0 = {
        .name   = "i2c-gpio",
        .id     = 0,
@@ -32,7 +41,7 @@ static struct platform_device nhk8815_i2c_dev0 = {
                .platform_data = &nhk8815_i2c_data0,
        },
 };
-/* second bus: GPIO XX and YY */
+
 static struct platform_device nhk8815_i2c_dev1 = {
        .name   = "i2c-gpio",
        .id     = 1,
@@ -41,15 +50,29 @@ static struct platform_device nhk8815_i2c_dev1 = {
        },
 };
 
+static struct platform_device nhk8815_i2c_dev2 = {
+       .name   = "i2c-gpio",
+       .id     = 2,
+       .dev    = {
+               .platform_data = &nhk8815_i2c_data2,
+       },
+};
+
+static pin_cfg_t cpu8815_pins_i2c[] = {
+       PIN_CFG_INPUT(62, GPIO, PULLUP),
+       PIN_CFG_INPUT(63, GPIO, PULLUP),
+       PIN_CFG_INPUT(53, GPIO, PULLUP),
+       PIN_CFG_INPUT(54, GPIO, PULLUP),
+       PIN_CFG_INPUT(73, GPIO, PULLUP),
+       PIN_CFG_INPUT(74, GPIO, PULLUP),
+};
+
 static int __init nhk8815_i2c_init(void)
 {
-       nmk_gpio_set_mode(nhk8815_i2c_data0.scl_pin, NMK_GPIO_ALT_GPIO);
-       nmk_gpio_set_mode(nhk8815_i2c_data0.sda_pin, NMK_GPIO_ALT_GPIO);
+       nmk_config_pins(cpu8815_pins_i2c, ARRAY_SIZE(cpu8815_pins_i2c));
        platform_device_register(&nhk8815_i2c_dev0);
-
-       nmk_gpio_set_mode(nhk8815_i2c_data1.scl_pin, NMK_GPIO_ALT_GPIO);
-       nmk_gpio_set_mode(nhk8815_i2c_data1.sda_pin, NMK_GPIO_ALT_GPIO);
        platform_device_register(&nhk8815_i2c_dev1);
+       platform_device_register(&nhk8815_i2c_dev2);
 
        return 0;
 }
@@ -58,6 +81,7 @@ static void __exit nhk8815_i2c_exit(void)
 {
        platform_device_unregister(&nhk8815_i2c_dev0);
        platform_device_unregister(&nhk8815_i2c_dev1);
+       platform_device_unregister(&nhk8815_i2c_dev2);
        return;
 }
 
index 8faabc5603987bed9237c2f8c2a8d9e0c5aeb6b6..a118e615f8650a81b100348abbbae3bc30b7c0ea 100644 (file)
 
 #include <mach/hardware.h>
 
-#define IRQ_VIC_START          0       /* first VIC interrupt is 0 */
+#define IRQ_VIC_START          1       /* first VIC interrupt is 1 */
 
 /*
  * Interrupt numbers generic for all Nomadik Chip cuts
  */
-#define IRQ_WATCHDOG                   0
-#define IRQ_SOFTINT                    1
-#define IRQ_CRYPTO                     2
-#define IRQ_OWM                                3
-#define IRQ_MTU0                       4
-#define IRQ_MTU1                       5
-#define IRQ_GPIO0                      6
-#define IRQ_GPIO1                      7
-#define IRQ_GPIO2                      8
-#define IRQ_GPIO3                      9
-#define IRQ_RTC_RTT                    10
-#define IRQ_SSP                                11
-#define IRQ_UART0                      12
-#define IRQ_DMA1                       13
-#define IRQ_CLCD_MDIF                  14
-#define IRQ_DMA0                       15
-#define IRQ_PWRFAIL                    16
-#define IRQ_UART1                      17
-#define IRQ_FIRDA                      18
-#define IRQ_MSP0                       19
-#define IRQ_I2C0                       20
-#define IRQ_I2C1                       21
-#define IRQ_SDMMC                      22
-#define IRQ_USBOTG                     23
-#define IRQ_SVA_IT0                    24
-#define IRQ_SVA_IT1                    25
-#define IRQ_SAA_IT0                    26
-#define IRQ_SAA_IT1                    27
-#define IRQ_UART2                      28
-#define IRQ_MSP2                       31
-#define IRQ_L2CC                       48
-#define IRQ_HPI                                49
-#define IRQ_SKE                                50
-#define IRQ_KP                         51
-#define IRQ_MEMST                      54
-#define IRQ_SGA_IT                     58
-#define IRQ_USBM                       60
-#define IRQ_MSP1                       62
+#define IRQ_WATCHDOG                   1
+#define IRQ_SOFTINT                    2
+#define IRQ_CRYPTO                     3
+#define IRQ_OWM                                4
+#define IRQ_MTU0                       5
+#define IRQ_MTU1                       6
+#define IRQ_GPIO0                      7
+#define IRQ_GPIO1                      8
+#define IRQ_GPIO2                      9
+#define IRQ_GPIO3                      10
+#define IRQ_RTC_RTT                    11
+#define IRQ_SSP                                12
+#define IRQ_UART0                      13
+#define IRQ_DMA1                       14
+#define IRQ_CLCD_MDIF                  15
+#define IRQ_DMA0                       16
+#define IRQ_PWRFAIL                    17
+#define IRQ_UART1                      18
+#define IRQ_FIRDA                      19
+#define IRQ_MSP0                       20
+#define IRQ_I2C0                       21
+#define IRQ_I2C1                       22
+#define IRQ_SDMMC                      23
+#define IRQ_USBOTG                     24
+#define IRQ_SVA_IT0                    25
+#define IRQ_SVA_IT1                    26
+#define IRQ_SAA_IT0                    27
+#define IRQ_SAA_IT1                    28
+#define IRQ_UART2                      29
+#define IRQ_MSP2                       30
+#define IRQ_L2CC                       49
+#define IRQ_HPI                                50
+#define IRQ_SKE                                51
+#define IRQ_KP                         52
+#define IRQ_MEMST                      55
+#define IRQ_SGA_IT                     59
+#define IRQ_USBM                       61
+#define IRQ_MSP1                       63
 
-#define NOMADIK_SOC_NR_IRQS            64
+#define NOMADIK_GPIO_OFFSET            (IRQ_VIC_START+64)
 
 /* After chip-specific IRQ numbers we have the GPIO ones */
 #define NOMADIK_NR_GPIO                        128 /* last 4 not wired to pins */
-#define NOMADIK_GPIO_TO_IRQ(gpio)      ((gpio) + NOMADIK_SOC_NR_IRQS)
-#define NOMADIK_IRQ_TO_GPIO(irq)       ((irq) - NOMADIK_SOC_NR_IRQS)
+#define NOMADIK_GPIO_TO_IRQ(gpio)      ((gpio) + NOMADIK_GPIO_OFFSET)
+#define NOMADIK_IRQ_TO_GPIO(irq)       ((irq) - NOMADIK_GPIO_OFFSET)
 #define NR_IRQS                                NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
 
 /* Following two are used by entry_macro.S, to access our dual-vic */
@@ -79,4 +79,3 @@
 #define VIC_REG_IRQSR1         0x20
 
 #endif /* __ASM_ARCH_IRQS_H */
-
index 90d0f85afba50ef9cf4ede71b8b7ef434f6510f1..dd0fbf76ac793d87580c1d750bad8983a25ef62e 100644 (file)
@@ -39,6 +39,7 @@ config ARCH_OMAP3
        select CPU_V7
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
        select ARCH_HAS_OPP
+       select PM_RUNTIME if CPU_IDLE
        select PM_OPP if PM
        select ARM_CPU_SUSPEND if PM
        select MULTI_IRQ_HANDLER
@@ -57,6 +58,7 @@ config ARCH_OMAP4
        select PL310_ERRATA_727915
        select ARM_ERRATA_720789
        select ARCH_HAS_OPP
+       select PM_RUNTIME if CPU_IDLE
        select PM_OPP if PM
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
        select ARM_CPU_SUSPEND if PM
index 238c5a3954b8fe7e4ae3e94aa0adb4931262eb96..b779ddd86faf285ad42c0a6de2d6c75dbc18e164 100644 (file)
@@ -71,10 +71,8 @@ ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)               += pm24xx.o
 obj-$(CONFIG_ARCH_OMAP2)               += sleep24xx.o
 obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o
-obj-$(CONFIG_ARCH_OMAP3)               += cpuidle34xx.o
 obj-$(CONFIG_ARCH_OMAP4)               += pm44xx.o omap-mpuss-lowpower.o
 obj-$(CONFIG_SOC_OMAP5)                        += omap-mpuss-lowpower.o
-obj-$(CONFIG_ARCH_OMAP4)               += cpuidle44xx.o
 obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
 obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
 obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3)  += smartreflex-class3.o
@@ -88,6 +86,11 @@ endif
 
 endif
 
+ifeq ($(CONFIG_CPU_IDLE),y)
+obj-$(CONFIG_ARCH_OMAP3)                += cpuidle34xx.o
+obj-$(CONFIG_ARCH_OMAP4)                += cpuidle44xx.o
+endif
+
 # PRCM
 omap-prcm-4-5-common                   =  prcm.o cminst44xx.o cm44xx.o \
                                           prcm_mpu44xx.o prminst44xx.o \
index 447682c4e11cccad255241f2f32240d41c1f1423..2c90ac6866868ac97b1dc22c519a12ef2553255c 100644 (file)
  * General Public License for more details.
  */
 
-#include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/davinci_emac.h>
-#include <linux/platform_device.h>
-#include <plat/irqs.h>
+#include <asm/system.h>
+#include <plat/omap_device.h>
 #include <mach/am35xx.h>
-
 #include "control.h"
-
-static struct mdio_platform_data am35xx_emac_mdio_pdata;
-
-static struct resource am35xx_emac_mdio_resources[] = {
-       DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET, SZ_4K),
-};
-
-static struct platform_device am35xx_emac_mdio_device = {
-       .name           = "davinci_mdio",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(am35xx_emac_mdio_resources),
-       .resource       = am35xx_emac_mdio_resources,
-       .dev.platform_data = &am35xx_emac_mdio_pdata,
-};
+#include "am35xx-emac.h"
 
 static void am35xx_enable_emac_int(void)
 {
@@ -69,41 +55,57 @@ static struct emac_platform_data am35xx_emac_pdata = {
        .interrupt_disable      = am35xx_disable_emac_int,
 };
 
-static struct resource am35xx_emac_resources[] = {
-       DEFINE_RES_MEM(AM35XX_IPSS_EMAC_BASE, 0x30000),
-       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RXTHRESH_IRQ),
-       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_RX_PULSE_IRQ),
-       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_TX_PULSE_IRQ),
-       DEFINE_RES_IRQ(INT_35XX_EMAC_C0_MISC_PULSE_IRQ),
-};
+static struct mdio_platform_data am35xx_mdio_pdata;
 
-static struct platform_device am35xx_emac_device = {
-       .name           = "davinci_emac",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(am35xx_emac_resources),
-       .resource       = am35xx_emac_resources,
-       .dev            = {
-               .platform_data  = &am35xx_emac_pdata,
-       },
-};
+static int __init omap_davinci_emac_dev_init(struct omap_hwmod *oh,
+               void *pdata, int pdata_len)
+{
+       struct platform_device *pdev;
+
+       pdev = omap_device_build(oh->class->name, 0, oh, pdata, pdata_len,
+                                NULL, 0, false);
+       if (IS_ERR(pdev)) {
+               WARN(1, "Can't build omap_device for %s:%s.\n",
+                    oh->class->name, oh->name);
+               return PTR_ERR(pdev);
+       }
+
+       return 0;
+}
 
 void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
 {
+       struct omap_hwmod *oh;
        u32 v;
-       int err;
+       int ret;
 
-       am35xx_emac_pdata.rmii_en = rmii_en;
-       am35xx_emac_mdio_pdata.bus_freq = mdio_bus_freq;
-       err = platform_device_register(&am35xx_emac_device);
-       if (err) {
-               pr_err("AM35x: failed registering EMAC device: %d\n", err);
+       oh = omap_hwmod_lookup("davinci_mdio");
+       if (!oh) {
+               pr_err("Could not find davinci_mdio hwmod\n");
+               return;
+       }
+
+       am35xx_mdio_pdata.bus_freq = mdio_bus_freq;
+
+       ret = omap_davinci_emac_dev_init(oh, &am35xx_mdio_pdata,
+                                        sizeof(am35xx_mdio_pdata));
+       if (ret) {
+               pr_err("Could not build davinci_mdio hwmod device\n");
                return;
        }
 
-       err = platform_device_register(&am35xx_emac_mdio_device);
-       if (err) {
-               pr_err("AM35x: failed registering EMAC MDIO device: %d\n", err);
-               platform_device_unregister(&am35xx_emac_device);
+       oh = omap_hwmod_lookup("davinci_emac");
+       if (!oh) {
+               pr_err("Could not find davinci_emac hwmod\n");
+               return;
+       }
+
+       am35xx_emac_pdata.rmii_en = rmii_en;
+
+       ret = omap_davinci_emac_dev_init(oh, &am35xx_emac_pdata,
+                                        sizeof(am35xx_emac_pdata));
+       if (ret) {
+               pr_err("Could not build davinci_emac hwmod device\n");
                return;
        }
 
index 6523aeabf9f2886684011dfa2657668da3b18fe8..9511584fdc4fd75bccd809e33ed354aedc8b791a 100644 (file)
@@ -218,9 +218,6 @@ static struct twl4030_gpio_platform_data sdp2430_gpio_data = {
 };
 
 static struct twl4030_platform_data sdp2430_twldata = {
-       .irq_base       = TWL4030_IRQ_BASE,
-       .irq_end        = TWL4030_IRQ_END,
-
        /* platform_data for children goes here */
        .gpio           = &sdp2430_gpio_data,
        .vmmc1          = &sdp2430_vmmc1,
index 580fd17208dacc24dd51bbff63507763c0612730..6202fc76e490f108e9ae238ae8499eab6cf1126a 100644 (file)
@@ -433,7 +433,7 @@ static struct platform_device *omap3_beagle_devices[] __initdata = {
 
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
 
-       .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
+       .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
        .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
        .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
 
index 932e1778aff94187c4ff2056c11f489747061c27..fca93d1afd43536a5ffca0d62248ac85f8f804c7 100644 (file)
@@ -93,9 +93,6 @@ static struct twl4030_usb_data omap3logic_usb_data = {
 
 
 static struct twl4030_platform_data omap3logic_twldata = {
-       .irq_base       = TWL4030_IRQ_BASE,
-       .irq_end        = TWL4030_IRQ_END,
-
        /* platform_data for children goes here */
        .gpio           = &omap3logic_gpio_data,
        .vmmc1          = &omap3logic_vmmc1,
index 8fa2fc3a4c3c51e973eb07c91f3c687c86aca62a..779734d8ba37304417350cd246c52044a0238897 100644 (file)
@@ -494,8 +494,8 @@ static void __init overo_init(void)
 
        regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-       omap_hsmmc_init(mmc);
        overo_i2c_init();
+       omap_hsmmc_init(mmc);
        omap_display_init(&overo_dss_data);
        omap_serial_init();
        omap_sdrc_init(mt46h32m32lf6_sdrc_params,
index 7300982a8e0e7279ba482755d538c73c52b9db60..c3e91d0dd2f273dc185be149c5253ba92a4a380d 100644 (file)
@@ -2490,13 +2490,13 @@ static struct clk uart4_fck = {
 };
 
 static struct clk uart4_fck_am35xx = {
-       .name           = "uart4_fck",
-       .ops            = &clkops_omap2_dflt_wait,
-       .parent         = &per_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
-       .enable_bit     = OMAP3430_EN_UART4_SHIFT,
-       .clkdm_name     = "core_l4_clkdm",
-       .recalc         = &followparent_recalc,
+       .name           = "uart4_fck",
+       .ops            = &clkops_omap2_dflt_wait,
+       .parent         = &core_48m_fck,
+       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .enable_bit     = AM35XX_EN_UART4_SHIFT,
+       .clkdm_name     = "core_l4_clkdm",
+       .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt2_fck = {
@@ -3201,8 +3201,12 @@ static struct clk vpfe_fck = {
 };
 
 /*
- * The UART1/2 functional clock acts as the functional
- * clock for UART4. No separate fclk control available.
+ * The UART1/2 functional clock acts as the functional clock for
+ * UART4. No separate fclk control available.  XXX Well now we have a
+ * uart4_fck that is apparently used as the UART4 functional clock,
+ * but it also seems that uart1_fck or uart2_fck are still needed, at
+ * least for UART4 softresets to complete.  This really needs
+ * clarification.
  */
 static struct clk uart4_ick_am35xx = {
        .name           = "uart4_ick",
@@ -3464,12 +3468,12 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "ipss_ick",     &ipss_ick,      CK_AM35XX),
        CLK(NULL,       "rmii_ck",      &rmii_ck,       CK_AM35XX),
        CLK(NULL,       "pclk_ck",      &pclk_ck,       CK_AM35XX),
-       CLK("davinci_emac",     NULL,   &emac_ick,      CK_AM35XX),
+       CLK("davinci_emac.0",   NULL,   &emac_ick,      CK_AM35XX),
        CLK("davinci_mdio.0",   NULL,   &emac_fck,      CK_AM35XX),
        CLK("vpfe-capture",     "master",       &vpfe_ick,      CK_AM35XX),
        CLK("vpfe-capture",     "slave",        &vpfe_fck,      CK_AM35XX),
-       CLK("musb-am35x",       "ick",          &hsotgusb_ick_am35xx,   CK_AM35XX),
-       CLK("musb-am35x",       "fck",          &hsotgusb_fck_am35xx,   CK_AM35XX),
+       CLK(NULL,       "hsotgusb_ick",         &hsotgusb_ick_am35xx,   CK_AM35XX),
+       CLK(NULL,       "hsotgusb_fck",         &hsotgusb_fck_am35xx,   CK_AM35XX),
        CLK(NULL,       "hecc_ck",      &hecc_ck,       CK_AM35XX),
        CLK(NULL,       "uart4_ick",    &uart4_ick_am35xx,      CK_AM35XX),
        CLK(NULL,       "timer_32k_ck", &omap_32k_fck,  CK_3XXX),
index 0a8c7b67858cbe3d07e7139c81cb5749cf09e5e0..5601dc13785ed606f0ce1bdf562472270489811a 100644 (file)
  *
  * CLKDM_NO_AUTODEPS: Prevent "autodeps" from being added/removed from this
  *     clockdomain.  (Currently, this applies to OMAP3 clockdomains only.)
+ * CLKDM_ACTIVE_WITH_MPU: The PRCM guarantees that this clockdomain is
+ *     active whenever the MPU is active.  True for interconnects and
+ *     the WKUP clockdomains.
  */
 #define CLKDM_CAN_FORCE_SLEEP                  (1 << 0)
 #define CLKDM_CAN_FORCE_WAKEUP                 (1 << 1)
 #define CLKDM_CAN_ENABLE_AUTO                  (1 << 2)
 #define CLKDM_CAN_DISABLE_AUTO                 (1 << 3)
 #define CLKDM_NO_AUTODEPS                      (1 << 4)
+#define CLKDM_ACTIVE_WITH_MPU                  (1 << 5)
 
 #define CLKDM_CAN_HWSUP                (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO)
 #define CLKDM_CAN_SWSUP                (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP)
index 839145e1cfbea2bcf706e72be39da268e6778247..4972219653ce85b1bebcad5629ab92d733dfef45 100644 (file)
@@ -88,4 +88,5 @@ struct clockdomain wkup_common_clkdm = {
        .name           = "wkup_clkdm",
        .pwrdm          = { .name = "wkup_pwrdm" },
        .dep_bit        = OMAP_EN_WKUP_SHIFT,
+       .flags          = CLKDM_ACTIVE_WITH_MPU,
 };
index 2cdc17c9d2fa34dc40c7a0473f67828d4a9acc5a..56089c49142a9e810a11ca0e60bbcf62f0fae7da 100644 (file)
@@ -59,6 +59,12 @@ static struct clkdm_dep gfx_sgx_3xxx_wkdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep gfx_sgx_am35x_wkdeps[] = {
+       { .clkdm_name = "mpu_clkdm" },
+       { .clkdm_name = "wkup_clkdm" },
+       { NULL },
+};
+
 /* 3430: PM_WKDEP_PER: CORE, IVA2, MPU, WKUP */
 static struct clkdm_dep per_wkdeps[] = {
        { .clkdm_name = "core_l3_clkdm" },
@@ -69,6 +75,14 @@ static struct clkdm_dep per_wkdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep per_am35x_wkdeps[] = {
+       { .clkdm_name = "core_l3_clkdm" },
+       { .clkdm_name = "core_l4_clkdm" },
+       { .clkdm_name = "mpu_clkdm" },
+       { .clkdm_name = "wkup_clkdm" },
+       { NULL },
+};
+
 /* 3430ES2: PM_WKDEP_USBHOST: CORE, IVA2, MPU, WKUP */
 static struct clkdm_dep usbhost_wkdeps[] = {
        { .clkdm_name = "core_l3_clkdm" },
@@ -79,6 +93,14 @@ static struct clkdm_dep usbhost_wkdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep usbhost_am35x_wkdeps[] = {
+       { .clkdm_name = "core_l3_clkdm" },
+       { .clkdm_name = "core_l4_clkdm" },
+       { .clkdm_name = "mpu_clkdm" },
+       { .clkdm_name = "wkup_clkdm" },
+       { NULL },
+};
+
 /* 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER */
 static struct clkdm_dep mpu_3xxx_wkdeps[] = {
        { .clkdm_name = "core_l3_clkdm" },
@@ -89,6 +111,14 @@ static struct clkdm_dep mpu_3xxx_wkdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep mpu_am35x_wkdeps[] = {
+       { .clkdm_name = "core_l3_clkdm" },
+       { .clkdm_name = "core_l4_clkdm" },
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "per_clkdm" },
+       { NULL },
+};
+
 /* 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER */
 static struct clkdm_dep iva2_wkdeps[] = {
        { .clkdm_name = "core_l3_clkdm" },
@@ -116,6 +146,12 @@ static struct clkdm_dep dss_wkdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep dss_am35x_wkdeps[] = {
+       { .clkdm_name = "mpu_clkdm" },
+       { .clkdm_name = "wkup_clkdm" },
+       { NULL },
+};
+
 /* 3430: PM_WKDEP_NEON: MPU */
 static struct clkdm_dep neon_wkdeps[] = {
        { .clkdm_name = "mpu_clkdm" },
@@ -131,6 +167,11 @@ static struct clkdm_dep dss_sleepdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep dss_am35x_sleepdeps[] = {
+       { .clkdm_name = "mpu_clkdm" },
+       { NULL },
+};
+
 /* 3430: CM_SLEEPDEP_PER: MPU, IVA */
 static struct clkdm_dep per_sleepdeps[] = {
        { .clkdm_name = "mpu_clkdm" },
@@ -138,6 +179,11 @@ static struct clkdm_dep per_sleepdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep per_am35x_sleepdeps[] = {
+       { .clkdm_name = "mpu_clkdm" },
+       { NULL },
+};
+
 /* 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA */
 static struct clkdm_dep usbhost_sleepdeps[] = {
        { .clkdm_name = "mpu_clkdm" },
@@ -145,6 +191,11 @@ static struct clkdm_dep usbhost_sleepdeps[] = {
        { NULL },
 };
 
+static struct clkdm_dep usbhost_am35x_sleepdeps[] = {
+       { .clkdm_name = "mpu_clkdm" },
+       { NULL },
+};
+
 /* 3430: CM_SLEEPDEP_CAM: MPU */
 static struct clkdm_dep cam_sleepdeps[] = {
        { .clkdm_name = "mpu_clkdm" },
@@ -175,6 +226,15 @@ static struct clockdomain mpu_3xxx_clkdm = {
        .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK,
 };
 
+static struct clockdomain mpu_am35x_clkdm = {
+       .name           = "mpu_clkdm",
+       .pwrdm          = { .name = "mpu_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP | CLKDM_CAN_FORCE_WAKEUP,
+       .dep_bit        = OMAP3430_EN_MPU_SHIFT,
+       .wkdep_srcs     = mpu_am35x_wkdeps,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK,
+};
+
 static struct clockdomain neon_clkdm = {
        .name           = "neon_clkdm",
        .pwrdm          = { .name = "neon_pwrdm" },
@@ -210,6 +270,15 @@ static struct clockdomain sgx_clkdm = {
        .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK,
 };
 
+static struct clockdomain sgx_am35x_clkdm = {
+       .name           = "sgx_clkdm",
+       .pwrdm          = { .name = "sgx_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .wkdep_srcs     = gfx_sgx_am35x_wkdeps,
+       .sleepdep_srcs  = gfx_sgx_sleepdeps,
+       .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK,
+};
+
 /*
  * The die-to-die clockdomain was documented in the 34xx ES1 TRM, but
  * then that information was removed from the 34xx ES2+ TRM.  It is
@@ -261,6 +330,16 @@ static struct clockdomain dss_3xxx_clkdm = {
        .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK,
 };
 
+static struct clockdomain dss_am35x_clkdm = {
+       .name           = "dss_clkdm",
+       .pwrdm          = { .name = "dss_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .dep_bit        = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT,
+       .wkdep_srcs     = dss_am35x_wkdeps,
+       .sleepdep_srcs  = dss_am35x_sleepdeps,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK,
+};
+
 static struct clockdomain cam_clkdm = {
        .name           = "cam_clkdm",
        .pwrdm          = { .name = "cam_pwrdm" },
@@ -279,6 +358,15 @@ static struct clockdomain usbhost_clkdm = {
        .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK,
 };
 
+static struct clockdomain usbhost_am35x_clkdm = {
+       .name           = "usbhost_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .wkdep_srcs     = usbhost_am35x_wkdeps,
+       .sleepdep_srcs  = usbhost_am35x_sleepdeps,
+       .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK,
+};
+
 static struct clockdomain per_clkdm = {
        .name           = "per_clkdm",
        .pwrdm          = { .name = "per_pwrdm" },
@@ -289,6 +377,16 @@ static struct clockdomain per_clkdm = {
        .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK,
 };
 
+static struct clockdomain per_am35x_clkdm = {
+       .name           = "per_clkdm",
+       .pwrdm          = { .name = "per_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .dep_bit        = OMAP3430_EN_PER_SHIFT,
+       .wkdep_srcs     = per_am35x_wkdeps,
+       .sleepdep_srcs  = per_am35x_sleepdeps,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK,
+};
+
 /*
  * Disable hw supervised mode for emu_clkdm, because emu_pwrdm is
  * switched of even if sdti is in use
@@ -341,29 +439,42 @@ static struct clkdm_autodep clkdm_autodeps[] = {
        }
 };
 
+static struct clkdm_autodep clkdm_am35x_autodeps[] = {
+       {
+               .clkdm = { .name = "mpu_clkdm" },
+       },
+       {
+               .clkdm = { .name = NULL },
+       }
+};
+
 /*
  *
  */
 
-static struct clockdomain *clockdomains_omap3430_common[] __initdata = {
+static struct clockdomain *clockdomains_common[] __initdata = {
        &wkup_common_clkdm,
-       &mpu_3xxx_clkdm,
        &neon_clkdm,
-       &iva2_clkdm,
-       &d2d_clkdm,
        &core_l3_3xxx_clkdm,
        &core_l4_3xxx_clkdm,
-       &dss_3xxx_clkdm,
-       &cam_clkdm,
-       &per_clkdm,
        &emu_clkdm,
        &dpll1_clkdm,
-       &dpll2_clkdm,
        &dpll3_clkdm,
        &dpll4_clkdm,
        NULL
 };
 
+static struct clockdomain *clockdomains_omap3430[] __initdata = {
+       &mpu_3xxx_clkdm,
+       &iva2_clkdm,
+       &d2d_clkdm,
+       &dss_3xxx_clkdm,
+       &cam_clkdm,
+       &per_clkdm,
+       &dpll2_clkdm,
+       NULL
+};
+
 static struct clockdomain *clockdomains_omap3430es1[] __initdata = {
        &gfx_3430es1_clkdm,
        NULL,
@@ -376,21 +487,41 @@ static struct clockdomain *clockdomains_omap3430es2plus[] __initdata = {
        NULL,
 };
 
+static struct clockdomain *clockdomains_am35x[] __initdata = {
+       &mpu_am35x_clkdm,
+       &sgx_am35x_clkdm,
+       &dss_am35x_clkdm,
+       &per_am35x_clkdm,
+       &usbhost_am35x_clkdm,
+       &dpll5_clkdm,
+       NULL
+};
+
 void __init omap3xxx_clockdomains_init(void)
 {
        struct clockdomain **sc;
+       unsigned int rev;
 
        if (!cpu_is_omap34xx())
                return;
 
        clkdm_register_platform_funcs(&omap3_clkdm_operations);
-       clkdm_register_clkdms(clockdomains_omap3430_common);
+       clkdm_register_clkdms(clockdomains_common);
 
-       sc = (omap_rev() == OMAP3430_REV_ES1_0) ? clockdomains_omap3430es1 :
-               clockdomains_omap3430es2plus;
+       rev = omap_rev();
 
-       clkdm_register_clkdms(sc);
+       if (rev == AM35XX_REV_ES1_0 || rev == AM35XX_REV_ES1_1) {
+               clkdm_register_clkdms(clockdomains_am35x);
+               clkdm_register_autodeps(clkdm_am35x_autodeps);
+       } else {
+               clkdm_register_clkdms(clockdomains_omap3430);
+
+               sc = (rev == OMAP3430_REV_ES1_0) ?
+                       clockdomains_omap3430es1 : clockdomains_omap3430es2plus;
+
+               clkdm_register_clkdms(sc);
+               clkdm_register_autodeps(clkdm_autodeps);
+       }
 
-       clkdm_register_autodeps(clkdm_autodeps);
        clkdm_complete_init();
 }
index bd7ed13515cc75c78662ef8adb323b693407247f..63d60a773d3b2e51e7e65bd6131a207871daa0dc 100644 (file)
@@ -381,7 +381,7 @@ static struct clockdomain l4_wkup_44xx_clkdm = {
        .cm_inst          = OMAP4430_PRM_WKUP_CM_INST,
        .clkdm_offs       = OMAP4430_PRM_WKUP_CM_WKUP_CDOFFS,
        .dep_bit          = OMAP4430_L4WKUP_STATDEP_SHIFT,
-       .flags            = CLKDM_CAN_HWSUP,
+       .flags            = CLKDM_CAN_HWSUP | CLKDM_ACTIVE_WITH_MPU,
 };
 
 static struct clockdomain emu_sys_44xx_clkdm = {
index 8083a8cdc55f074aad48a88e8a2c2f7605c8f333..766338fe4d347746ee04eb3961452a7b3f8f6aa9 100644 (file)
 /* AM35XX specific CM_ICLKEN1_CORE bits */
 #define AM35XX_EN_IPSS_MASK                            (1 << 4)
 #define AM35XX_EN_IPSS_SHIFT                           4
-#define AM35XX_EN_UART4_MASK                           (1 << 23)
-#define AM35XX_EN_UART4_SHIFT                          23
 
 /* CM_ICLKEN2_CORE */
 #define OMAP3430_EN_PKA_MASK                           (1 << 4)
 #define OMAP3430_ST_DES2_MASK                          (1 << 26)
 #define OMAP3430_ST_MSPRO_SHIFT                                23
 #define OMAP3430_ST_MSPRO_MASK                         (1 << 23)
+#define AM35XX_ST_UART4_SHIFT                          23
+#define AM35XX_ST_UART4_MASK                           (1 << 23)
 #define OMAP3430_ST_HDQ_SHIFT                          22
 #define OMAP3430_ST_HDQ_MASK                           (1 << 22)
 #define OMAP3430ES1_ST_FAC_SHIFT                       8
index 1706ebcec08d79c08ea23191b949266613c9406e..c1875862679fc7092044644bf83e6948ecdbe4c8 100644 (file)
@@ -63,28 +63,30 @@ void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
        struct spi_board_info *spi_bi = &ads7846_spi_board_info;
        int err;
 
-       if (board_pdata && board_pdata->get_pendown_state) {
-               err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown");
-               if (err) {
-                       pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err);
-                       return;
-               }
-               gpio_export(gpio_pendown, 0);
-
-               if (gpio_debounce)
-                       gpio_set_debounce(gpio_pendown, gpio_debounce);
+       err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown");
+       if (err) {
+               pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err);
+               return;
        }
 
+       if (gpio_debounce)
+               gpio_set_debounce(gpio_pendown, gpio_debounce);
+
        spi_bi->bus_num = bus_num;
        spi_bi->irq     = gpio_to_irq(gpio_pendown);
 
        if (board_pdata) {
                board_pdata->gpio_pendown = gpio_pendown;
                spi_bi->platform_data = board_pdata;
+               if (board_pdata->get_pendown_state)
+                       gpio_export(gpio_pendown, 0);
        } else {
                ads7846_config.gpio_pendown = gpio_pendown;
        }
 
+       if (!board_pdata || (board_pdata && !board_pdata->get_pendown_state))
+               gpio_free(gpio_pendown);
+
        spi_register_board_info(&ads7846_spi_board_info, 1);
 }
 #else
index 207bc1c7759f1bb66b986d0ff1dbadd8c2b01925..31344528eb5448905f46252228fc6cdb22a2a4e3 100644 (file)
@@ -36,8 +36,6 @@
 #include "control.h"
 #include "common.h"
 
-#ifdef CONFIG_CPU_IDLE
-
 /* Mach specific information to be recorded in the C-state driver_data */
 struct omap3_idle_statedata {
        u32 mpu_state;
@@ -379,9 +377,3 @@ int __init omap3_idle_init(void)
 
        return 0;
 }
-#else
-int __init omap3_idle_init(void)
-{
-       return 0;
-}
-#endif /* CONFIG_CPU_IDLE */
index be1617ca84bd022092e7c06849a3ece28e64052f..02d15bbd4e35c2eb4d90cf892085d143d0334e81 100644 (file)
@@ -22,8 +22,6 @@
 #include "pm.h"
 #include "prm.h"
 
-#ifdef CONFIG_CPU_IDLE
-
 /* Machine specific information */
 struct omap4_idle_statedata {
        u32 cpu_state;
@@ -199,9 +197,3 @@ int __init omap4_idle_init(void)
 
        return 0;
 }
-#else
-int __init omap4_idle_init(void)
-{
-       return 0;
-}
-#endif /* CONFIG_CPU_IDLE */
index be3e059a4017f16654f06514f05eda0d0213cb7e..71651e20a43ed0e784222c5242dba428641eb299 100644 (file)
@@ -772,7 +772,7 @@ static int __init omap_init_wdt(void)
        char *oh_name = "wd_timer2";
        char *dev_name = "omap_wdt";
 
-       if (!cpu_class_is_omap2())
+       if (!cpu_class_is_omap2() || of_have_populated_dt())
                return 0;
 
        oh = omap_hwmod_lookup(oh_name);
index f1e13d1ca5e7360b30878de8b69c5dd6c2a3adf3..95594495fcf6481f5568c8ed43787eb977d1a2ab 100644 (file)
@@ -36,6 +36,8 @@
 #define AM35XX_EMAC_CNTRL_MOD_OFFSET   (0x0)
 #define AM35XX_EMAC_CNTRL_RAM_OFFSET   (0x20000)
 #define AM35XX_EMAC_MDIO_OFFSET                (0x30000)
+#define AM35XX_IPSS_MDIO_BASE          (AM35XX_IPSS_EMAC_BASE + \
+                                               AM35XX_EMAC_MDIO_OFFSET)
 #define AM35XX_EMAC_CNTRL_RAM_SIZE     (0x2000)
 #define AM35XX_EMAC_RAM_ADDR           (AM3517_EMAC_BASE + \
                                                AM3517_EMAC_CNTRL_RAM_OFFSET)
index 8467beb122b5a73d9c9f8d335635346371eb49ac..bcd83db41bbce706062a9116d5aa1fb25472089e 100644 (file)
@@ -263,7 +263,7 @@ int __init intc_of_init(struct device_node *node,
                             struct device_node *parent)
 {
        struct resource res;
-       u32 nr_irqs = 96;
+       u32 nr_irq = 96;
 
        if (WARN_ON(!node))
                return -ENODEV;
@@ -273,10 +273,10 @@ int __init intc_of_init(struct device_node *node,
                return -EINVAL;
        }
 
-       if (of_property_read_u32(node, "ti,intc-size", &nr_irqs))
-               pr_warn("unable to get intc-size, default to %d\n", nr_irqs);
+       if (of_property_read_u32(node, "ti,intc-size", &nr_irq))
+               pr_warn("unable to get intc-size, default to %d\n", nr_irq);
 
-       omap_init_irq(res.start, nr_irqs, of_node_get(node));
+       omap_init_irq(res.start, nr_irq, of_node_get(node));
 
        return 0;
 }
index 19b8b6774862dce41d3b837db885573b0d9d26e0..6875be837d9f9632cb3ffbd0c3fcbd64b5dcfddc 100644 (file)
@@ -83,8 +83,6 @@ static int omap2_mbox_startup(struct omap_mbox *mbox)
        l = mbox_read_reg(MAILBOX_REVISION);
        pr_debug("omap mailbox rev %d.%d\n", (l & 0xf0) >> 4, (l & 0x0f));
 
-       omap2_mbox_enable_irq(mbox, IRQ_RX);
-
        return 0;
 }
 
index ac49384d028521deceb8e11355b46fbd4a2ec1b9..1be8bcb52e9307cdacffea26857db68a762927cd 100644 (file)
@@ -73,19 +73,17 @@ static struct iommu_device omap4_devices[] = {
                        .da_end = 0xFFFFF000,
                },
        },
-#if defined(CONFIG_MPU_TESLA_IOMMU)
        {
                .base = OMAP4_MMU2_BASE,
-               .irq = INT_44XX_DSP_MMU,
+               .irq = OMAP44XX_IRQ_TESLA_MMU,
                .pdata = {
                        .name = "tesla",
                        .nr_tlb_entries = 32,
-                       .clk_name = "tesla_ick",
+                       .clk_name = "dsp_fck",
                        .da_start = 0x0,
                        .da_end = 0xFFFFF000,
                },
        },
-#endif
 };
 #define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices)
 static struct platform_device *omap4_iommu_pdev[NR_OMAP4_IOMMU_DEVICES];
index 2ada3642c671222dba4c9acefa14b9eb85d33273..3f21568f17535cb9aebaaff15ce0416e13d7ccb0 100644 (file)
@@ -1188,15 +1188,18 @@ static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap
  * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
  * @oh: struct omap_hwmod *
  *
- * If module is marked as SWSUP_SIDLE, force the module out of slave
- * idle; otherwise, configure it for smart-idle.  If module is marked
- * as SWSUP_MSUSPEND, force the module out of master standby;
- * otherwise, configure it for smart-standby.  No return value.
+ * Ensure that the OCP_SYSCONFIG register for the IP block represented
+ * by @oh is set to indicate to the PRCM that the IP block is active.
+ * Usually this means placing the module into smart-idle mode and
+ * smart-standby, but if there is a bug in the automatic idle handling
+ * for the IP block, it may need to be placed into the force-idle or
+ * no-idle variants of these modes.  No return value.
  */
 static void _enable_sysc(struct omap_hwmod *oh)
 {
        u8 idlemode, sf;
        u32 v;
+       bool clkdm_act;
 
        if (!oh->class->sysc)
                return;
@@ -1205,8 +1208,16 @@ static void _enable_sysc(struct omap_hwmod *oh)
        sf = oh->class->sysc->sysc_flags;
 
        if (sf & SYSC_HAS_SIDLEMODE) {
-               idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ?
-                       HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART;
+               clkdm_act = ((oh->clkdm &&
+                             oh->clkdm->flags & CLKDM_ACTIVE_WITH_MPU) ||
+                            (oh->_clk && oh->_clk->clkdm &&
+                             oh->_clk->clkdm->flags & CLKDM_ACTIVE_WITH_MPU));
+               if (clkdm_act && !(oh->class->sysc->idlemodes &
+                                  (SIDLE_SMART | SIDLE_SMART_WKUP)))
+                       idlemode = HWMOD_IDLEMODE_FORCE;
+               else
+                       idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ?
+                               HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART;
                _set_slave_idlemode(oh, idlemode, &v);
        }
 
@@ -1272,8 +1283,13 @@ static void _idle_sysc(struct omap_hwmod *oh)
        sf = oh->class->sysc->sysc_flags;
 
        if (sf & SYSC_HAS_SIDLEMODE) {
-               idlemode = (oh->flags & HWMOD_SWSUP_SIDLE) ?
-                       HWMOD_IDLEMODE_FORCE : HWMOD_IDLEMODE_SMART;
+               /* XXX What about HWMOD_IDLEMODE_SMART_WKUP? */
+               if (oh->flags & HWMOD_SWSUP_SIDLE ||
+                   !(oh->class->sysc->idlemodes &
+                     (SIDLE_SMART | SIDLE_SMART_WKUP)))
+                       idlemode = HWMOD_IDLEMODE_FORCE;
+               else
+                       idlemode = HWMOD_IDLEMODE_SMART;
                _set_slave_idlemode(oh, idlemode, &v);
        }
 
index 6491e057d9ce72676157fd2f3a06f816c2724a05..cdb9637aab19d26d5b1acf1a7601a122b963663c 100644 (file)
@@ -519,11 +519,27 @@ static struct omap_hwmod omap36xx_uart4_hwmod = {
 
 static struct omap_hwmod_irq_info am35xx_uart4_mpu_irqs[] = {
        { .irq = INT_35XX_UART4_IRQ, },
+       { .irq = -1 }
 };
 
 static struct omap_hwmod_dma_info am35xx_uart4_sdma_reqs[] = {
        { .name = "rx", .dma_req = AM35XX_DMA_UART4_RX, },
        { .name = "tx", .dma_req = AM35XX_DMA_UART4_TX, },
+       { .dma_req = -1 }
+};
+
+/*
+ * XXX AM35xx UART4 cannot complete its softreset without uart1_fck or
+ * uart2_fck being enabled.  So we add uart1_fck as an optional clock,
+ * below, and set the HWMOD_CONTROL_OPT_CLKS_IN_RESET.  This really
+ * should not be needed.  The functional clock structure of the AM35xx
+ * UART4 is extremely unclear and opaque; it is unclear what the role
+ * of uart1/2_fck is for the UART4.  Any clarification from either
+ * empirical testing or the AM3505/3517 hardware designers would be
+ * most welcome.
+ */
+static struct omap_hwmod_opt_clk am35xx_uart4_opt_clks[] = {
+       { .role = "softreset_uart1_fck", .clk = "uart1_fck" },
 };
 
 static struct omap_hwmod am35xx_uart4_hwmod = {
@@ -535,11 +551,14 @@ static struct omap_hwmod am35xx_uart4_hwmod = {
                .omap2 = {
                        .module_offs = CORE_MOD,
                        .prcm_reg_id = 1,
-                       .module_bit = OMAP3430_EN_UART4_SHIFT,
+                       .module_bit = AM35XX_EN_UART4_SHIFT,
                        .idlest_reg_id = 1,
-                       .idlest_idle_bit = OMAP3430_EN_UART4_SHIFT,
+                       .idlest_idle_bit = AM35XX_ST_UART4_SHIFT,
                },
        },
+       .opt_clks       = am35xx_uart4_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(am35xx_uart4_opt_clks),
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
        .class          = &omap2_uart_class,
 };
 
@@ -1651,25 +1670,20 @@ static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
 
 /* usb_otg_hs */
 static struct omap_hwmod_irq_info am35xx_usbhsotg_mpu_irqs[] = {
-
        { .name = "mc", .irq = 71 },
        { .irq = -1 }
 };
 
 static struct omap_hwmod_class am35xx_usbotg_class = {
        .name = "am35xx_usbotg",
-       .sysc = NULL,
 };
 
 static struct omap_hwmod am35xx_usbhsotg_hwmod = {
        .name           = "am35x_otg_hs",
        .mpu_irqs       = am35xx_usbhsotg_mpu_irqs,
-       .main_clk       = NULL,
-       .prcm = {
-               .omap2 = {
-               },
-       },
+       .main_clk       = "hsotgusb_fck",
        .class          = &am35xx_usbotg_class,
+       .flags          = HWMOD_NO_IDLEST,
 };
 
 /* MMC/SD/SDIO common */
@@ -2110,9 +2124,10 @@ static struct omap_hwmod_ocp_if omap3xxx_usbhsotg__l3 = {
 static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
        .master         = &am35xx_usbhsotg_hwmod,
        .slave          = &omap3xxx_l3_main_hwmod,
-       .clk            = "core_l3_ick",
+       .clk            = "hsotgusb_ick",
        .user           = OCP_USER_MPU,
 };
+
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
        .master = &omap3xxx_l4_core_hwmod,
@@ -2256,6 +2271,7 @@ static struct omap_hwmod_addr_space am35xx_uart4_addr_space[] = {
                .pa_end         = OMAP3_UART4_AM35XX_BASE + SZ_1K - 1,
                .flags          = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
        },
+       { }
 };
 
 static struct omap_hwmod_ocp_if am35xx_l4_core__uart4 = {
@@ -2406,7 +2422,7 @@ static struct omap_hwmod_addr_space am35xx_usbhsotg_addrs[] = {
 static struct omap_hwmod_ocp_if am35xx_l4_core__usbhsotg = {
        .master         = &omap3xxx_l4_core_hwmod,
        .slave          = &am35xx_usbhsotg_hwmod,
-       .clk            = "l4_ick",
+       .clk            = "hsotgusb_ick",
        .addr           = am35xx_usbhsotg_addrs,
        .user           = OCP_USER_MPU,
 };
@@ -3151,6 +3167,107 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__counter_32k = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* am35xx has Davinci MDIO & EMAC */
+static struct omap_hwmod_class am35xx_mdio_class = {
+       .name = "davinci_mdio",
+};
+
+static struct omap_hwmod am35xx_mdio_hwmod = {
+       .name           = "davinci_mdio",
+       .class          = &am35xx_mdio_class,
+       .flags          = HWMOD_NO_IDLEST,
+};
+
+/*
+ * XXX Should be connected to an IPSS hwmod, not the L3 directly;
+ * but this will probably require some additional hwmod core support,
+ * so is left as a future to-do item.
+ */
+static struct omap_hwmod_ocp_if am35xx_mdio__l3 = {
+       .master         = &am35xx_mdio_hwmod,
+       .slave          = &omap3xxx_l3_main_hwmod,
+       .clk            = "emac_fck",
+       .user           = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am35xx_mdio_addrs[] = {
+       {
+               .pa_start       = AM35XX_IPSS_MDIO_BASE,
+               .pa_end         = AM35XX_IPSS_MDIO_BASE + SZ_4K - 1,
+               .flags          = ADDR_TYPE_RT,
+       },
+       { }
+};
+
+/* l4_core -> davinci mdio  */
+/*
+ * XXX Should be connected to an IPSS hwmod, not the L4_CORE directly;
+ * but this will probably require some additional hwmod core support,
+ * so is left as a future to-do item.
+ */
+static struct omap_hwmod_ocp_if am35xx_l4_core__mdio = {
+       .master         = &omap3xxx_l4_core_hwmod,
+       .slave          = &am35xx_mdio_hwmod,
+       .clk            = "emac_fck",
+       .addr           = am35xx_mdio_addrs,
+       .user           = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_irq_info am35xx_emac_mpu_irqs[] = {
+       { .name = "rxthresh",   .irq = INT_35XX_EMAC_C0_RXTHRESH_IRQ },
+       { .name = "rx_pulse",   .irq = INT_35XX_EMAC_C0_RX_PULSE_IRQ },
+       { .name = "tx_pulse",   .irq = INT_35XX_EMAC_C0_TX_PULSE_IRQ },
+       { .name = "misc_pulse", .irq = INT_35XX_EMAC_C0_MISC_PULSE_IRQ },
+       { .irq = -1 }
+};
+
+static struct omap_hwmod_class am35xx_emac_class = {
+       .name = "davinci_emac",
+};
+
+static struct omap_hwmod am35xx_emac_hwmod = {
+       .name           = "davinci_emac",
+       .mpu_irqs       = am35xx_emac_mpu_irqs,
+       .class          = &am35xx_emac_class,
+       .flags          = HWMOD_NO_IDLEST,
+};
+
+/* l3_core -> davinci emac interface */
+/*
+ * XXX Should be connected to an IPSS hwmod, not the L3 directly;
+ * but this will probably require some additional hwmod core support,
+ * so is left as a future to-do item.
+ */
+static struct omap_hwmod_ocp_if am35xx_emac__l3 = {
+       .master         = &am35xx_emac_hwmod,
+       .slave          = &omap3xxx_l3_main_hwmod,
+       .clk            = "emac_ick",
+       .user           = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am35xx_emac_addrs[] = {
+       {
+               .pa_start       = AM35XX_IPSS_EMAC_BASE,
+               .pa_end         = AM35XX_IPSS_EMAC_BASE + 0x30000 - 1,
+               .flags          = ADDR_TYPE_RT,
+       },
+       { }
+};
+
+/* l4_core -> davinci emac  */
+/*
+ * XXX Should be connected to an IPSS hwmod, not the L4_CORE directly;
+ * but this will probably require some additional hwmod core support,
+ * so is left as a future to-do item.
+ */
+static struct omap_hwmod_ocp_if am35xx_l4_core__emac = {
+       .master         = &omap3xxx_l4_core_hwmod,
+       .slave          = &am35xx_emac_hwmod,
+       .clk            = "emac_ick",
+       .addr           = am35xx_emac_addrs,
+       .user           = OCP_USER_MPU,
+};
+
 static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
        &omap3xxx_l3_main__l4_core,
        &omap3xxx_l3_main__l4_per,
@@ -3279,6 +3396,10 @@ static struct omap_hwmod_ocp_if *am35xx_hwmod_ocp_ifs[] __initdata = {
        &omap3xxx_l4_core__usb_tll_hs,
        &omap3xxx_l4_core__es3plus_mmc1,
        &omap3xxx_l4_core__es3plus_mmc2,
+       &am35xx_mdio__l3,
+       &am35xx_l4_core__mdio,
+       &am35xx_emac__l3,
+       &am35xx_l4_core__emac,
        NULL
 };
 
index 1b1d04141c3d695cef78c294301f1e10a18df29a..5c2ce7e7783828737ab9abaf41f1b20325391ebe 100644 (file)
@@ -1928,7 +1928,7 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp1_sdma_reqs[] = {
 
 static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
        { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_clk", .clk = "mcbsp1_sync_mux_ck" },
+       { .role = "prcm_fck", .clk = "mcbsp1_sync_mux_ck" },
 };
 
 static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
@@ -1963,7 +1963,7 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp2_sdma_reqs[] = {
 
 static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
        { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_clk", .clk = "mcbsp2_sync_mux_ck" },
+       { .role = "prcm_fck", .clk = "mcbsp2_sync_mux_ck" },
 };
 
 static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
@@ -1998,7 +1998,7 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp3_sdma_reqs[] = {
 
 static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
        { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_clk", .clk = "mcbsp3_sync_mux_ck" },
+       { .role = "prcm_fck", .clk = "mcbsp3_sync_mux_ck" },
 };
 
 static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
@@ -2033,7 +2033,7 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp4_sdma_reqs[] = {
 
 static struct omap_hwmod_opt_clk mcbsp4_opt_clks[] = {
        { .role = "pad_fck", .clk = "pad_clks_ck" },
-       { .role = "prcm_clk", .clk = "mcbsp4_sync_mux_ck" },
+       { .role = "prcm_fck", .clk = "mcbsp4_sync_mux_ck" },
 };
 
 static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
@@ -3855,7 +3855,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = {
 };
 
 /* usb_host_fs -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_usb_host_fs__l3_main_2 = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_usb_host_fs__l3_main_2 = {
        .master         = &omap44xx_usb_host_fs_hwmod,
        .slave          = &omap44xx_l3_main_2_hwmod,
        .clk            = "l3_div_ck",
@@ -3913,7 +3913,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = {
 };
 
 /* aess -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_aess__l4_abe = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_aess__l4_abe = {
        .master         = &omap44xx_aess_hwmod,
        .slave          = &omap44xx_l4_abe_hwmod,
        .clk            = "ocp_abe_iclk",
@@ -4004,7 +4004,7 @@ static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
 };
 
 /* l4_abe -> aess */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_abe__aess = {
        .master         = &omap44xx_l4_abe_hwmod,
        .slave          = &omap44xx_aess_hwmod,
        .clk            = "ocp_abe_iclk",
@@ -4022,7 +4022,7 @@ static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
 };
 
 /* l4_abe -> aess (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess_dma = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_abe__aess_dma = {
        .master         = &omap44xx_l4_abe_hwmod,
        .slave          = &omap44xx_aess_hwmod,
        .clk            = "ocp_abe_iclk",
@@ -5848,7 +5848,7 @@ static struct omap_hwmod_addr_space omap44xx_usb_host_fs_addrs[] = {
 };
 
 /* l4_cfg -> usb_host_fs */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_fs = {
+static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l4_cfg__usb_host_fs = {
        .master         = &omap44xx_l4_cfg_hwmod,
        .slave          = &omap44xx_usb_host_fs_hwmod,
        .clk            = "l4_div_ck",
@@ -6005,13 +6005,13 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_iva__l3_main_2,
        &omap44xx_l3_main_1__l3_main_2,
        &omap44xx_l4_cfg__l3_main_2,
-       &omap44xx_usb_host_fs__l3_main_2,
+       /* &omap44xx_usb_host_fs__l3_main_2, */
        &omap44xx_usb_host_hs__l3_main_2,
        &omap44xx_usb_otg_hs__l3_main_2,
        &omap44xx_l3_main_1__l3_main_3,
        &omap44xx_l3_main_2__l3_main_3,
        &omap44xx_l4_cfg__l3_main_3,
-       &omap44xx_aess__l4_abe,
+       /* &omap44xx_aess__l4_abe, */
        &omap44xx_dsp__l4_abe,
        &omap44xx_l3_main_1__l4_abe,
        &omap44xx_mpu__l4_abe,
@@ -6020,8 +6020,8 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_cfg__l4_wkup,
        &omap44xx_mpu__mpu_private,
        &omap44xx_l4_cfg__ocp_wp_noc,
-       &omap44xx_l4_abe__aess,
-       &omap44xx_l4_abe__aess_dma,
+       /* &omap44xx_l4_abe__aess, */
+       /* &omap44xx_l4_abe__aess_dma, */
        &omap44xx_l3_main_2__c2c,
        &omap44xx_l4_wkup__counter_32k,
        &omap44xx_l4_cfg__ctrl_module_core,
@@ -6127,7 +6127,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
        &omap44xx_l4_per__uart2,
        &omap44xx_l4_per__uart3,
        &omap44xx_l4_per__uart4,
-       &omap44xx_l4_cfg__usb_host_fs,
+       /* &omap44xx_l4_cfg__usb_host_fs, */
        &omap44xx_l4_cfg__usb_host_hs,
        &omap44xx_l4_cfg__usb_otg_hs,
        &omap44xx_l4_cfg__usb_tll_hs,
index de6d46451746eaa19f2ba2a28c6385531acddce3..d8f6dbf45d16c32cd4f542a762d764af61406c23 100644 (file)
@@ -53,7 +53,7 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def,
        omap_table_init = 1;
 
        /* Lets now register with OPP library */
-       for (i = 0; i < opp_def_size; i++) {
+       for (i = 0; i < opp_def_size; i++, opp_def++) {
                struct omap_hwmod *oh;
                struct device *dev;
 
@@ -86,7 +86,6 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def,
                                        __func__, opp_def->freq,
                                        opp_def->hwmod_name, i, r);
                }
-               opp_def++;
        }
 
        return 0;
index 78564895e9144c327420034d5a4f3f6c9b3f44b8..ab04d3bba2e756dc573c621a8fe68058402be2bb 100644 (file)
 
 #include "powerdomain.h"
 
+#ifdef CONFIG_CPU_IDLE
+extern int __init omap3_idle_init(void);
+extern int __init omap4_idle_init(void);
+#else
+static inline int omap3_idle_init(void)
+{
+       return 0;
+}
+
+static inline int omap4_idle_init(void)
+{
+       return 0;
+}
+#endif
+
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
 extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
-extern int omap3_idle_init(void);
-extern int omap4_idle_init(void);
 extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
 extern int (*omap_pm_suspend)(void);
 
index 3a595e8997245495672d703fc52c7a148ffb0a9f..9b463c987508740e876749674c4b5e63e94f53b6 100644 (file)
@@ -581,10 +581,13 @@ static void __init prcm_setup_regs(void)
                          OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
 
        /* Don't attach IVA interrupts */
-       omap2_prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
-       omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
-       omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
-       omap2_prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
+       if (omap3_has_iva()) {
+               omap2_prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
+               omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
+               omap2_prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
+               omap2_prm_write_mod_reg(0, OMAP3430_PER_MOD,
+                                       OMAP3430_PM_IVAGRPSEL);
+       }
 
        /* Clear any pending 'reset' flags */
        omap2_prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST);
@@ -598,7 +601,9 @@ static void __init prcm_setup_regs(void)
        /* Clear any pending PRCM interrupts */
        omap2_prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
 
-       omap3_iva_idle();
+       if (omap3_has_iva())
+               omap3_iva_idle();
+
        omap3_d2d_idle();
 }
 
index fb0a0a6869d17b783834f93616ba29a2f3430e43..bb883e463078b264869594d150dc5a2bb49d0caf 100644 (file)
@@ -71,6 +71,22 @@ static struct powerdomain mpu_3xxx_pwrdm = {
        .voltdm           = { .name = "mpu_iva" },
 };
 
+static struct powerdomain mpu_am35x_pwrdm = {
+       .name             = "mpu_pwrdm",
+       .prcm_offs        = MPU_MOD,
+       .pwrsts           = PWRSTS_ON,
+       .pwrsts_logic_ret = PWRSTS_ON,
+       .flags            = PWRDM_HAS_MPU_QUIRK,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_ON,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_ON,
+       },
+       .voltdm           = { .name = "mpu_iva" },
+};
+
 /*
  * The USBTLL Save-and-Restore mechanism is broken on
  * 3430s up to ES3.0 and 3630ES1.0. Hence this feature
@@ -120,6 +136,23 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = {
        .voltdm           = { .name = "core" },
 };
 
+static struct powerdomain core_am35x_pwrdm = {
+       .name             = "core_pwrdm",
+       .prcm_offs        = CORE_MOD,
+       .pwrsts           = PWRSTS_ON,
+       .pwrsts_logic_ret = PWRSTS_ON,
+       .banks            = 2,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_ON,         /* MEM1RETSTATE */
+               [1] = PWRSTS_ON,         /* MEM2RETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_ON, /* MEM1ONSTATE */
+               [1] = PWRSTS_ON, /* MEM2ONSTATE */
+       },
+       .voltdm           = { .name = "core" },
+};
+
 static struct powerdomain dss_pwrdm = {
        .name             = "dss_pwrdm",
        .prcm_offs        = OMAP3430_DSS_MOD,
@@ -135,6 +168,21 @@ static struct powerdomain dss_pwrdm = {
        .voltdm           = { .name = "core" },
 };
 
+static struct powerdomain dss_am35x_pwrdm = {
+       .name             = "dss_pwrdm",
+       .prcm_offs        = OMAP3430_DSS_MOD,
+       .pwrsts           = PWRSTS_ON,
+       .pwrsts_logic_ret = PWRSTS_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_ON, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_ON,  /* MEMONSTATE */
+       },
+       .voltdm           = { .name = "core" },
+};
+
 /*
  * Although the 34XX TRM Rev K Table 4-371 notes that retention is a
  * possible SGX powerstate, the SGX device itself does not support
@@ -156,6 +204,21 @@ static struct powerdomain sgx_pwrdm = {
        .voltdm           = { .name = "core" },
 };
 
+static struct powerdomain sgx_am35x_pwrdm = {
+       .name             = "sgx_pwrdm",
+       .prcm_offs        = OMAP3430ES2_SGX_MOD,
+       .pwrsts           = PWRSTS_ON,
+       .pwrsts_logic_ret = PWRSTS_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_ON, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_ON,  /* MEMONSTATE */
+       },
+       .voltdm           = { .name = "core" },
+};
+
 static struct powerdomain cam_pwrdm = {
        .name             = "cam_pwrdm",
        .prcm_offs        = OMAP3430_CAM_MOD,
@@ -186,6 +249,21 @@ static struct powerdomain per_pwrdm = {
        .voltdm           = { .name = "core" },
 };
 
+static struct powerdomain per_am35x_pwrdm = {
+       .name             = "per_pwrdm",
+       .prcm_offs        = OMAP3430_PER_MOD,
+       .pwrsts           = PWRSTS_ON,
+       .pwrsts_logic_ret = PWRSTS_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_ON, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_ON,  /* MEMONSTATE */
+       },
+       .voltdm           = { .name = "core" },
+};
+
 static struct powerdomain emu_pwrdm = {
        .name           = "emu_pwrdm",
        .prcm_offs      = OMAP3430_EMU_MOD,
@@ -200,6 +278,14 @@ static struct powerdomain neon_pwrdm = {
        .voltdm           = { .name = "mpu_iva" },
 };
 
+static struct powerdomain neon_am35x_pwrdm = {
+       .name             = "neon_pwrdm",
+       .prcm_offs        = OMAP3430_NEON_MOD,
+       .pwrsts           = PWRSTS_ON,
+       .pwrsts_logic_ret = PWRSTS_ON,
+       .voltdm           = { .name = "mpu_iva" },
+};
+
 static struct powerdomain usbhost_pwrdm = {
        .name             = "usbhost_pwrdm",
        .prcm_offs        = OMAP3430ES2_USBHOST_MOD,
@@ -293,6 +379,22 @@ static struct powerdomain *powerdomains_omap3430es3_1plus[] __initdata = {
        NULL
 };
 
+static struct powerdomain *powerdomains_am35x[] __initdata = {
+       &wkup_omap2_pwrdm,
+       &mpu_am35x_pwrdm,
+       &neon_am35x_pwrdm,
+       &core_am35x_pwrdm,
+       &sgx_am35x_pwrdm,
+       &dss_am35x_pwrdm,
+       &per_am35x_pwrdm,
+       &emu_pwrdm,
+       &dpll1_pwrdm,
+       &dpll3_pwrdm,
+       &dpll4_pwrdm,
+       &dpll5_pwrdm,
+       NULL
+};
+
 void __init omap3xxx_powerdomains_init(void)
 {
        unsigned int rev;
@@ -301,21 +403,34 @@ void __init omap3xxx_powerdomains_init(void)
                return;
 
        pwrdm_register_platform_funcs(&omap3_pwrdm_operations);
-       pwrdm_register_pwrdms(powerdomains_omap3430_common);
 
        rev = omap_rev();
 
-       if (rev == OMAP3430_REV_ES1_0)
-               pwrdm_register_pwrdms(powerdomains_omap3430es1);
-       else if (rev == OMAP3430_REV_ES2_0 || rev == OMAP3430_REV_ES2_1 ||
-                rev == OMAP3430_REV_ES3_0 || rev == OMAP3630_REV_ES1_0)
-               pwrdm_register_pwrdms(powerdomains_omap3430es2_es3_0);
-       else if (rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2 ||
-                rev == AM35XX_REV_ES1_0 || rev == AM35XX_REV_ES1_1 ||
-                rev == OMAP3630_REV_ES1_1 || rev == OMAP3630_REV_ES1_2)
-               pwrdm_register_pwrdms(powerdomains_omap3430es3_1plus);
-       else
-               WARN(1, "OMAP3 powerdomain init: unknown chip type\n");
+       if (rev == AM35XX_REV_ES1_0 || rev == AM35XX_REV_ES1_1) {
+               pwrdm_register_pwrdms(powerdomains_am35x);
+       } else {
+               pwrdm_register_pwrdms(powerdomains_omap3430_common);
+
+               switch (rev) {
+               case OMAP3430_REV_ES1_0:
+                       pwrdm_register_pwrdms(powerdomains_omap3430es1);
+                       break;
+               case OMAP3430_REV_ES2_0:
+               case OMAP3430_REV_ES2_1:
+               case OMAP3430_REV_ES3_0:
+               case OMAP3630_REV_ES1_0:
+                       pwrdm_register_pwrdms(powerdomains_omap3430es2_es3_0);
+                       break;
+               case OMAP3430_REV_ES3_1:
+               case OMAP3430_REV_ES3_1_2:
+               case OMAP3630_REV_ES1_1:
+               case OMAP3630_REV_ES1_2:
+                       pwrdm_register_pwrdms(powerdomains_omap3430es3_1plus);
+                       break;
+               default:
+                       WARN(1, "OMAP3 powerdomain init: unknown chip type\n");
+               }
+       }
 
        pwrdm_complete_init();
 }
index 44485a8f2556431573ef3ab5f98877a20e57aae6..d5ae4e234bbc028d4563fe80f4f140dd772af81a 100644 (file)
 #define OMAP3430_EN_MMC2_SHIFT                         25
 #define OMAP3430_EN_MMC1_MASK                          (1 << 24)
 #define OMAP3430_EN_MMC1_SHIFT                         24
-#define OMAP3430_EN_UART4_MASK                         (1 << 23)
-#define OMAP3430_EN_UART4_SHIFT                                23
+#define AM35XX_EN_UART4_MASK                           (1 << 23)
+#define AM35XX_EN_UART4_SHIFT                          23
 #define OMAP3430_EN_MCSPI4_MASK                                (1 << 21)
 #define OMAP3430_EN_MCSPI4_SHIFT                       21
 #define OMAP3430_EN_MCSPI3_MASK                                (1 << 20)
index 663ade3b2f45b11f09f9c806d20e3d726bf8a345..03b126d9ad9427bbb5027b3c740e52ca89daba57 100644 (file)
@@ -85,7 +85,7 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
        unsigned long priority_pending[OMAP_PRCM_MAX_NR_PENDING_REG];
        struct irq_chip *chip = irq_desc_get_chip(desc);
        unsigned int virtirq;
-       int nr_irqs = prcm_irq_setup->nr_regs * 32;
+       int nr_irq = prcm_irq_setup->nr_regs * 32;
 
        /*
         * If we are suspended, mask all interrupts from PRCM level,
@@ -110,7 +110,7 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
                prcm_irq_setup->read_pending_irqs(pending);
 
                /* No bit set, then all IRQs are handled */
-               if (find_first_bit(pending, nr_irqs) >= nr_irqs)
+               if (find_first_bit(pending, nr_irq) >= nr_irq)
                        break;
 
                omap_prcm_events_filter_priority(pending, priority_pending);
@@ -121,11 +121,11 @@ static void omap_prcm_irq_handler(unsigned int irq, struct irq_desc *desc)
                 */
 
                /* Serve priority events first */
-               for_each_set_bit(virtirq, priority_pending, nr_irqs)
+               for_each_set_bit(virtirq, priority_pending, nr_irq)
                        generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
 
                /* Serve normal events next */
-               for_each_set_bit(virtirq, pending, nr_irqs)
+               for_each_set_bit(virtirq, pending, nr_irq)
                        generic_handle_irq(prcm_irq_setup->base_irq + virtirq);
        }
        if (chip->irq_ack)
index 119d5a910f3a4a7ef902b5a2cb4054edc1278d56..3882f3c7608cdbe77a89b826589b52c4ccfa284e 100644 (file)
@@ -32,6 +32,7 @@
 #include "twl-common.h"
 #include "pm.h"
 #include "voltage.h"
+#include "mux.h"
 
 static struct i2c_board_info __initdata pmic_i2c_board_info = {
        .addr           = 0x48,
@@ -48,6 +49,7 @@ static struct i2c_board_info __initdata omap4_i2c1_board_info[] = {
        },
 };
 
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
 static int twl_set_voltage(void *data, int target_uV)
 {
        struct voltagedomain *voltdm = (struct voltagedomain *)data;
@@ -59,6 +61,7 @@ static int twl_get_voltage(void *data)
        struct voltagedomain *voltdm = (struct voltagedomain *)data;
        return voltdm_get_voltage(voltdm);
 }
+#endif
 
 void __init omap_pmic_init(int bus, u32 clkrate,
                           const char *pmic_type, int pmic_irq,
@@ -77,6 +80,7 @@ void __init omap4_pmic_init(const char *pmic_type,
                    struct twl6040_platform_data *twl6040_data, int twl6040_irq)
 {
        /* PMIC part*/
+       omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
        strncpy(omap4_i2c1_board_info[0].type, pmic_type,
                sizeof(omap4_i2c1_board_info[0].type));
        omap4_i2c1_board_info[0].irq = OMAP44XX_IRQ_SYS_1N;
@@ -211,10 +215,6 @@ static struct twl_regulator_driver_data omap3_vdd2_drvdata = {
 void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
                                  u32 pdata_flags, u32 regulators_flags)
 {
-       if (!pmic_data->irq_base)
-               pmic_data->irq_base = TWL4030_IRQ_BASE;
-       if (!pmic_data->irq_end)
-               pmic_data->irq_end = TWL4030_IRQ_END;
        if (!pmic_data->vdd1) {
                omap3_vdd1.driver_data = &omap3_vdd1_drvdata;
                omap3_vdd1_drvdata.data = voltdm_lookup("mpu_iva");
@@ -479,11 +479,6 @@ static struct regulator_init_data omap4_v2v1_idata = {
 void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
                                  u32 pdata_flags, u32 regulators_flags)
 {
-       if (!pmic_data->irq_base)
-               pmic_data->irq_base = TWL6030_IRQ_BASE;
-       if (!pmic_data->irq_end)
-               pmic_data->irq_end = TWL6030_IRQ_END;
-
        if (!pmic_data->vdd1) {
                omap4_vdd1.driver_data = &omap4_vdd1_drvdata;
                omap4_vdd1_drvdata.data = voltdm_lookup("mpu");
index e5ec4a8d9bcb39e370a26742e237d3896dc0a20d..8e39f80fce1914a5da7a76a6dfeb22f64327e522 100644 (file)
@@ -1,2 +1 @@
 obj-y  := common.o
-obj-y  += time.o
index a2e8ae8b58214d6e702984e8b749b03ce3878acf..8f9a0b47a7fa8293860036c09516854109a310f1 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/dw_apb_timer.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/vic.h>
@@ -97,7 +98,7 @@ DT_MACHINE_START(PICOXCELL, "Picochip picoXcell")
        .nr_irqs        = NR_IRQS_LEGACY,
        .init_irq       = picoxcell_init_irq,
        .handle_irq     = vic_handle_irq,
-       .timer          = &picoxcell_timer,
+       .timer          = &dw_apb_timer,
        .init_machine   = picoxcell_init_machine,
        .dt_compat      = picoxcell_dt_match,
        .restart        = picoxcell_wdt_restart,
index 83d55ab956a49882979cd220507aa6327645c0e9..a65cb02f84c8d4824b319718942f3b71d7d2fae4 100644 (file)
@@ -12,6 +12,6 @@
 
 #include <asm/mach/time.h>
 
-extern struct sys_timer picoxcell_timer;
+extern struct sys_timer dw_apb_timer;
 
 #endif /* __PICOXCELL_COMMON_H__ */
index d09da6a746b8a15d212e0e1aabcaeacbf8b480cc..d3de84b0dcbed280a27d12092509f6a9df4e181e 100644 (file)
@@ -127,7 +127,11 @@ static unsigned long hx4700_pin_config[] __initdata = {
        GPIO19_SSP2_SCLK,
        GPIO86_SSP2_RXD,
        GPIO87_SSP2_TXD,
-       GPIO88_GPIO,
+       GPIO88_GPIO | MFP_LPM_DRIVE_HIGH,       /* TSC2046_CS */
+
+       /* BQ24022 Regulator */
+       GPIO72_GPIO | MFP_LPM_KEEP_OUTPUT,      /* BQ24022_nCHARGE_EN */
+       GPIO96_GPIO | MFP_LPM_KEEP_OUTPUT,      /* BQ24022_ISET2 */
 
        /* HX4700 specific input GPIOs */
        GPIO12_GPIO | WAKEUP_ON_EDGE_RISE,      /* ASIC3_IRQ */
@@ -135,6 +139,10 @@ static unsigned long hx4700_pin_config[] __initdata = {
        GPIO14_GPIO,    /* nWLAN_IRQ */
 
        /* HX4700 specific output GPIOs */
+       GPIO61_GPIO | MFP_LPM_DRIVE_HIGH,       /* W3220_nRESET */
+       GPIO71_GPIO | MFP_LPM_DRIVE_HIGH,       /* ASIC3_nRESET */
+       GPIO81_GPIO | MFP_LPM_DRIVE_HIGH,       /* CPU_GP_nRESET */
+       GPIO116_GPIO | MFP_LPM_DRIVE_HIGH,      /* CPU_HW_nRESET */
        GPIO102_GPIO | MFP_LPM_DRIVE_LOW,       /* SYNAPTICS_POWER_ON */
 
        GPIO10_GPIO,    /* GSM_IRQ */
@@ -872,14 +880,19 @@ static struct gpio global_gpios[] = {
        { GPIO110_HX4700_LCD_LVDD_3V3_ON, GPIOF_OUT_INIT_HIGH, "LCD_LVDD" },
        { GPIO111_HX4700_LCD_AVDD_3V3_ON, GPIOF_OUT_INIT_HIGH, "LCD_AVDD" },
        { GPIO32_HX4700_RS232_ON,         GPIOF_OUT_INIT_HIGH, "RS232_ON" },
+       { GPIO61_HX4700_W3220_nRESET,     GPIOF_OUT_INIT_HIGH, "W3220_nRESET" },
        { GPIO71_HX4700_ASIC3_nRESET,     GPIOF_OUT_INIT_HIGH, "ASIC3_nRESET" },
+       { GPIO81_HX4700_CPU_GP_nRESET,    GPIOF_OUT_INIT_HIGH, "CPU_GP_nRESET" },
        { GPIO82_HX4700_EUART_RESET,      GPIOF_OUT_INIT_HIGH, "EUART_RESET" },
+       { GPIO116_HX4700_CPU_HW_nRESET,   GPIOF_OUT_INIT_HIGH, "CPU_HW_nRESET" },
 };
 
 static void __init hx4700_init(void)
 {
        int ret;
 
+       PCFR = PCFR_GPR_EN | PCFR_OPDE;
+
        pxa2xx_mfp_config(ARRAY_AND_SIZE(hx4700_pin_config));
        gpio_set_wake(GPIO12_HX4700_ASIC3_IRQ, 1);
        ret = gpio_request_array(ARRAY_AND_SIZE(global_gpios));
index 8702ecfaab3098f3987cd4bc6c23a2bc88a07a8e..14a81c2317a417eb14b3fc413678a5541e9b09a5 100644 (file)
@@ -144,7 +144,8 @@ static struct clk_lookup s3c2416_clk_lookup[] = {
        CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk),
        CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk),
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk2", &hsspi_mux.clk),
+       /* s3c2443-spi.0 is used on s3c2416 and s3c2450 as well */
+       CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &hsspi_mux.clk),
 };
 
 void __init s3c2416_init_clocks(int xtal)
index 414364eb426cf70d58a439b7e99b15e26c91a0c7..cb2883d553b5e53c320588eb740d435e111d0758 100644 (file)
@@ -106,7 +106,7 @@ static struct clk s3c2440_clk_cam_upll = {
 static struct clk s3c2440_clk_ac97 = {
        .name           = "ac97",
        .enable         = s3c2410_clkcon_enable,
-       .ctrlbit        = S3C2440_CLKCON_CAMERA,
+       .ctrlbit        = S3C2440_CLKCON_AC97,
 };
 
 static unsigned long  s3c2440_fclk_n_getrate(struct clk *clk)
index a4c5a520d9942abe648af870f978e79ebf15bab4..7f689ce1be614b7f2b7d43a860168f677b22d330 100644 (file)
@@ -181,7 +181,7 @@ static struct clk *clks[] __initdata = {
 
 static struct clk_lookup s3c2443_clk_lookup[] = {
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_hsmmc),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk2", &clk_hsspi.clk),
+       CLKDEV_INIT("s3c2443-spi.0", "spi_busclk2", &clk_hsspi.clk),
 };
 
 void __init s3c2443_init_clocks(int xtal)
index aeeb2be283fae341492bbe08efb3a44298182ebb..aeb4a24ff3edffb7cb79f308cc85911c555427e0 100644 (file)
@@ -559,7 +559,7 @@ static struct clk hsmmc1_clk = {
 
 static struct clk hsspi_clk = {
        .name           = "spi",
-       .devname        = "s3c64xx-spi.0",
+       .devname        = "s3c2443-spi.0",
        .parent         = &clk_p,
        .enable         = s3c2443_clkcon_enable_p,
        .ctrlbit        = S3C2443_PCLKCON_HSSPI,
@@ -633,7 +633,7 @@ static struct clk_lookup s3c2443_clk_lookup[] = {
        CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
        CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk),
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &hsspi_clk),
+       CLKDEV_INIT("s3c2443-spi.0", "spi_busclk0", &hsspi_clk),
 };
 
 void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
index 084604be6ad1317c8b58e78e96d878e291b53bb4..87e75a250d5eafe84cf4586fbaf0a563ab00ed96 100644 (file)
@@ -182,19 +182,21 @@ static struct platform_device __initdata *smdk_devs[] = {
        &smdk_led7,
 };
 
+static const struct gpio smdk_led_gpios[] = {
+       { S3C2410_GPF(4), GPIOF_OUT_INIT_HIGH, NULL },
+       { S3C2410_GPF(5), GPIOF_OUT_INIT_HIGH, NULL },
+       { S3C2410_GPF(6), GPIOF_OUT_INIT_HIGH, NULL },
+       { S3C2410_GPF(7), GPIOF_OUT_INIT_HIGH, NULL },
+};
+
 void __init smdk_machine_init(void)
 {
        /* Configure the LEDs (even if we have no LED support)*/
 
-       s3c_gpio_cfgpin(S3C2410_GPF(4), S3C2410_GPIO_OUTPUT);
-       s3c_gpio_cfgpin(S3C2410_GPF(5), S3C2410_GPIO_OUTPUT);
-       s3c_gpio_cfgpin(S3C2410_GPF(6), S3C2410_GPIO_OUTPUT);
-       s3c_gpio_cfgpin(S3C2410_GPF(7), S3C2410_GPIO_OUTPUT);
-
-       s3c2410_gpio_setpin(S3C2410_GPF(4), 1);
-       s3c2410_gpio_setpin(S3C2410_GPF(5), 1);
-       s3c2410_gpio_setpin(S3C2410_GPF(6), 1);
-       s3c2410_gpio_setpin(S3C2410_GPF(7), 1);
+       int ret = gpio_request_array(smdk_led_gpios,
+                                    ARRAY_SIZE(smdk_led_gpios));
+       if (!WARN_ON(ret < 0))
+               gpio_free_array(smdk_led_gpios, ARRAY_SIZE(smdk_led_gpios));
 
        if (machine_is_smdk2443())
                smdk_nand_info.twrph0 = 50;
index 56cdd34cce41ee3200b111a05bbf0a196acd86c0..0c9e9a785ef6e85d7e41260e09de23f1397a0871 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 #include <plat/regs-serial.h>
 
diff --git a/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h b/arch/arm/mach-s3c24xx/include/mach/bast-pmu.h
deleted file mode 100644 (file)
index 4c38b39..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/bast-pmu.h
- *
- * Copyright (c) 2003-2004 Simtec Electronics
- *     Ben Dooks <ben@simtec.co.uk>
- *     Vincent Sanders <vince@simtec.co.uk>
- *
- * Machine BAST - Power Management chip
- *
- * 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_ARCH_BASTPMU_H
-#define __ASM_ARCH_BASTPMU_H "08_OCT_2004"
-
-#define BASTPMU_REG_IDENT      (0x00)
-#define BASTPMU_REG_VERSION    (0x01)
-#define BASTPMU_REG_DDCCTRL    (0x02)
-#define BASTPMU_REG_POWER      (0x03)
-#define BASTPMU_REG_RESET      (0x04)
-#define BASTPMU_REG_GWO                (0x05)
-#define BASTPMU_REG_WOL                (0x06)
-#define BASTPMU_REG_WOR                (0x07)
-#define BASTPMU_REG_UID                (0x09)
-
-#define BASTPMU_EEPROM         (0xC0)
-
-#define BASTPMU_EEP_UID                (BASTPMU_EEPROM + 0)
-#define BASTPMU_EEP_WOL                (BASTPMU_EEPROM + 8)
-#define BASTPMU_EEP_WOR                (BASTPMU_EEPROM + 9)
-
-#define BASTPMU_IDENT_0                0x53
-#define BASTPMU_IDENT_1                0x42
-#define BASTPMU_IDENT_2                0x50
-#define BASTPMU_IDENT_3                0x4d
-
-#define BASTPMU_RESET_GUARD    (0x55)
-
-#endif /* __ASM_ARCH_BASTPMU_H */
index 019ea86057f69b4b7e383a3f871c13fb4d5fba0f..3890a05948fb1f8d8e8b4c5682feaea8f55b3574 100644 (file)
@@ -93,26 +93,5 @@ enum s3c_gpio_number {
 #define S3C2410_GPL(_nr)       (S3C2410_GPIO_L_START + (_nr))
 #define S3C2410_GPM(_nr)       (S3C2410_GPIO_M_START + (_nr))
 
-/* compatibility until drivers can be modified */
-
-#define S3C2410_GPA0   S3C2410_GPA(0)
-#define S3C2410_GPA1   S3C2410_GPA(1)
-#define S3C2410_GPA3   S3C2410_GPA(3)
-#define S3C2410_GPA7   S3C2410_GPA(7)
-
-#define S3C2410_GPE0   S3C2410_GPE(0)
-#define S3C2410_GPE1   S3C2410_GPE(1)
-#define S3C2410_GPE2   S3C2410_GPE(2)
-#define S3C2410_GPE3   S3C2410_GPE(3)
-#define S3C2410_GPE4   S3C2410_GPE(4)
-#define S3C2410_GPE5   S3C2410_GPE(5)
-#define S3C2410_GPE6   S3C2410_GPE(6)
-#define S3C2410_GPE7   S3C2410_GPE(7)
-#define S3C2410_GPE8   S3C2410_GPE(8)
-#define S3C2410_GPE9   S3C2410_GPE(9)
-#define S3C2410_GPE10  S3C2410_GPE(10)
-
-#define S3C2410_GPH10  S3C2410_GPH(10)
-
 #endif /* __MACH_GPIONRS_H */
 
index 3a56a229cac6634e47f3910e95dd21c99b527a50..2173934821533e8f1f70318e60040689429a07b4 100644 (file)
@@ -3,82 +3,13 @@
 
 #include <mach/regs-gpio.h>
 
-/* Different hardware revisions, passed in ATAG_REVISION by u-boot */
-#define GTA02v1_SYSTEM_REV     0x00000310
-#define GTA02v2_SYSTEM_REV     0x00000320
-#define GTA02v3_SYSTEM_REV     0x00000330
-#define GTA02v4_SYSTEM_REV     0x00000340
-#define GTA02v5_SYSTEM_REV     0x00000350
-/* since A7 is basically same as A6, we use A6 PCB ID */
-#define GTA02v6_SYSTEM_REV     0x00000360
-
-#define GTA02_GPIO_n3DL_GSM    S3C2410_GPA(13) /* v1 + v2 + v3 only */
-
-#define GTA02_GPIO_PWR_LED1    S3C2410_GPB(0)
-#define GTA02_GPIO_PWR_LED2    S3C2410_GPB(1)
 #define GTA02_GPIO_AUX_LED     S3C2410_GPB(2)
-#define GTA02_GPIO_VIBRATOR_ON S3C2410_GPB(3)
-#define GTA02_GPIO_MODEM_RST   S3C2410_GPB(5)
-#define GTA02_GPIO_BT_EN       S3C2410_GPB(6)
-#define GTA02_GPIO_MODEM_ON    S3C2410_GPB(7)
-#define GTA02_GPIO_EXTINT8     S3C2410_GPB(8)
 #define GTA02_GPIO_USB_PULLUP  S3C2410_GPB(9)
-
-#define GTA02_GPIO_PIO5                S3C2410_GPC(5)  /* v3 + v4 only */
-
-#define GTA02v3_GPIO_nG1_CS    S3C2410_GPD(12) /* v3 + v4 only */
-#define GTA02v3_GPIO_nG2_CS    S3C2410_GPD(13) /* v3 + v4 only */
-#define GTA02v5_GPIO_HDQ       S3C2410_GPD(14)   /* v5 + */
-
-#define GTA02_GPIO_nG1_INT     S3C2410_GPF(0)
-#define GTA02_GPIO_IO1         S3C2410_GPF(1)
-#define GTA02_GPIO_PIO_2       S3C2410_GPF(2)  /* v2 + v3 + v4 only */
-#define GTA02_GPIO_JACK_INSERT S3C2410_GPF(4)
-#define GTA02_GPIO_WLAN_GPIO1  S3C2410_GPF(5)  /* v2 + v3 + v4 only */
 #define GTA02_GPIO_AUX_KEY     S3C2410_GPF(6)
 #define GTA02_GPIO_HOLD_KEY    S3C2410_GPF(7)
-
-#define GTA02_GPIO_3D_IRQ      S3C2410_GPG(4)
-#define GTA02v2_GPIO_nG2_INT   S3C2410_GPG(8)  /* v2 + v3 + v4 only */
-#define GTA02v3_GPIO_nUSB_OC   S3C2410_GPG(9)  /* v3 + v4 only */
-#define GTA02v3_GPIO_nUSB_FLT  S3C2410_GPG(10) /* v3 + v4 only */
-#define GTA02v3_GPIO_nGSM_OC   S3C2410_GPG(11) /* v3 + v4 only */
-
 #define GTA02_GPIO_AMP_SHUT    S3C2410_GPJ(1)  /* v2 + v3 + v4 only */
-#define GTA02v1_GPIO_WLAN_GPIO10       S3C2410_GPJ(2)
 #define GTA02_GPIO_HP_IN       S3C2410_GPJ(2)  /* v2 + v3 + v4 only */
-#define GTA02_GPIO_INT0                S3C2410_GPJ(3)  /* v2 + v3 + v4 only */
-#define GTA02_GPIO_nGSM_EN     S3C2410_GPJ(4)
-#define GTA02_GPIO_3D_RESET    S3C2410_GPJ(5)
-#define GTA02_GPIO_nDL_GSM     S3C2410_GPJ(6)  /* v4 + v5 only */
-#define GTA02_GPIO_WLAN_GPIO0  S3C2410_GPJ(7)
-#define GTA02v1_GPIO_BAT_ID    S3C2410_GPJ(8)
-#define GTA02_GPIO_KEEPACT     S3C2410_GPJ(8)
-#define GTA02v1_GPIO_HP_IN     S3C2410_GPJ(10)
-#define GTA02_CHIP_PWD         S3C2410_GPJ(11) /* v2 + v3 + v4 only */
-#define GTA02_GPIO_nWLAN_RESET S3C2410_GPJ(12) /* v2 + v3 + v4 only */
 
-#define GTA02_IRQ_GSENSOR_1    IRQ_EINT0
-#define GTA02_IRQ_MODEM                IRQ_EINT1
-#define GTA02_IRQ_PIO_2                IRQ_EINT2       /* v2 + v3 + v4 only */
-#define GTA02_IRQ_nJACK_INSERT IRQ_EINT4
-#define GTA02_IRQ_WLAN_GPIO1   IRQ_EINT5
-#define GTA02_IRQ_AUX          IRQ_EINT6
-#define GTA02_IRQ_nHOLD                IRQ_EINT7
 #define GTA02_IRQ_PCF50633     IRQ_EINT9
-#define GTA02_IRQ_3D           IRQ_EINT12
-#define GTA02_IRQ_GSENSOR_2    IRQ_EINT16      /* v2 + v3 + v4 only */
-#define GTA02v3_IRQ_nUSB_OC    IRQ_EINT17      /* v3 + v4 only */
-#define GTA02v3_IRQ_nUSB_FLT   IRQ_EINT18      /* v3 + v4 only */
-#define GTA02v3_IRQ_nGSM_OC    IRQ_EINT19      /* v3 + v4 only */
-
-/* returns 00 000 on GTA02 A5 and earlier, A6 returns 01 001 */
-#define GTA02_PCB_ID1_0                S3C2410_GPC(13)
-#define GTA02_PCB_ID1_1                S3C2410_GPC(15)
-#define GTA02_PCB_ID1_2                S3C2410_GPD(0)
-#define GTA02_PCB_ID2_0                S3C2410_GPD(3)
-#define GTA02_PCB_ID2_1                S3C2410_GPD(4)
-
-int gta02_get_pcb_revision(void);
 
 #endif /* _GTA02_H */
index cac1ad6b582cc42aaede66ff65ca9931e4e58724..a11a638bd5996368a9bc28b265462e19496e3d92 100644 (file)
 /* S3C2410:
  * Port G consists of 8 GPIO/IRQ/Special function
  *
- * GPGCON has 2 bits for each of the input pins on port F
+ * GPGCON has 2 bits for each of the input pins on port G
  *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
  *
  * pull up works like all other ports.
 
 /* Port H consists of11 GPIO/serial/Misc pins
  *
- * GPGCON has 2 bits for each of the input pins on port F
+ * GPHCON has 2 bits for each of the input pins on port H
  *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
  *
  * pull up works like all other ports.
  * for the 2412/2413 from the 2410/2440/2442
 */
 
+/*
+ * Port J consists of 13 GPIO/Camera pins. GPJCON has 2 bits
+ * for each of the pins on port J.
+ *   00 - input, 01 output, 10 - camera
+ *
+ * Pull up works like all other ports.
+ */
+
+#define S3C2413_GPJCON    S3C2410_GPIOREG(0x80)
+#define S3C2413_GPJDAT    S3C2410_GPIOREG(0x84)
+#define S3C2413_GPJUP     S3C2410_GPIOREG(0x88)
+#define S3C2413_GPJSLPCON  S3C2410_GPIOREG(0x8C)
+
 /* S3C2443 and above */
 #define S3C2440_GPJCON    S3C2410_GPIOREG(0xD0)
 #define S3C2440_GPJDAT    S3C2410_GPIOREG(0xD4)
diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpioj.h
deleted file mode 100644 (file)
index 19575e0..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-gpioj.h
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- *                   http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2440 GPIO J register definitions
-*/
-
-
-#ifndef __ASM_ARCH_REGS_GPIOJ_H
-#define __ASM_ARCH_REGS_GPIOJ_H "gpioj"
-
-/* Port J consists of 13 GPIO/Camera pins
- *
- * GPJCON has 2 bits for each of the input pins on port F
- *   00 = 0 input, 1 output, 2 Camera
- *
- * pull up works like all other ports.
-*/
-
-#define S3C2413_GPJCON         S3C2410_GPIOREG(0x80)
-#define S3C2413_GPJDAT         S3C2410_GPIOREG(0x84)
-#define S3C2413_GPJUP          S3C2410_GPIOREG(0x88)
-#define S3C2413_GPJSLPCON      S3C2410_GPIOREG(0x8C)
-
-#define S3C2440_GPJ0_OUTP       (0x01 << 0)
-#define S3C2440_GPJ0_CAMDATA0   (0x02 << 0)
-
-#define S3C2440_GPJ1_OUTP       (0x01 << 2)
-#define S3C2440_GPJ1_CAMDATA1   (0x02 << 2)
-
-#define S3C2440_GPJ2_OUTP       (0x01 << 4)
-#define S3C2440_GPJ2_CAMDATA2   (0x02 << 4)
-
-#define S3C2440_GPJ3_OUTP       (0x01 << 6)
-#define S3C2440_GPJ3_CAMDATA3   (0x02 << 6)
-
-#define S3C2440_GPJ4_OUTP       (0x01 << 8)
-#define S3C2440_GPJ4_CAMDATA4   (0x02 << 8)
-
-#define S3C2440_GPJ5_OUTP       (0x01 << 10)
-#define S3C2440_GPJ5_CAMDATA5   (0x02 << 10)
-
-#define S3C2440_GPJ6_OUTP       (0x01 << 12)
-#define S3C2440_GPJ6_CAMDATA6   (0x02 << 12)
-
-#define S3C2440_GPJ7_OUTP       (0x01 << 14)
-#define S3C2440_GPJ7_CAMDATA7   (0x02 << 14)
-
-#define S3C2440_GPJ8_OUTP       (0x01 << 16)
-#define S3C2440_GPJ8_CAMPCLK    (0x02 << 16)
-
-#define S3C2440_GPJ9_OUTP       (0x01 << 18)
-#define S3C2440_GPJ9_CAMVSYNC   (0x02 << 18)
-
-#define S3C2440_GPJ10_OUTP      (0x01 << 20)
-#define S3C2440_GPJ10_CAMHREF   (0x02 << 20)
-
-#define S3C2440_GPJ11_OUTP      (0x01 << 22)
-#define S3C2440_GPJ11_CAMCLKOUT (0x02 << 22)
-
-#define S3C2440_GPJ12_OUTP      (0x01 << 24)
-#define S3C2440_GPJ12_CAMRESET  (0x02 << 24)
-
-#endif /* __ASM_ARCH_REGS_GPIOJ_H */
-
index 0f29f64a3eeb8b98c3b3e6ccd394687cffe83b42..92e1f93a6bca73f9c0227e6bbd8c1283d452fe4e 100644 (file)
@@ -71,7 +71,6 @@
 
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
 #include <mach/fb.h>
 
 #include <plat/usb-control.h>
index f092b188ab70afba8e3012aad0b717c9936b97be..bd6d2525debef34a3d6e8752912bcb26da6cf52f 100644 (file)
@@ -634,8 +634,8 @@ static void __init mini2440_init(void)
        s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
 
        /* Turn the backlight early on */
-       WARN_ON(gpio_request(S3C2410_GPG(4), "backlight"));
-       gpio_direction_output(S3C2410_GPG(4), 1);
+       WARN_ON(gpio_request_one(S3C2410_GPG(4), GPIOF_OUT_INIT_HIGH, NULL));
+       gpio_free(S3C2410_GPG(4));
 
        /* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */
        s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
index b868dddcb836c318d4315feeaaef1f37a5e851da..678bbca2b5e5ae7738e5921b041afb80a0214af6 100644 (file)
@@ -47,7 +47,6 @@
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
-#include <mach/regs-gpio.h>
 #include <mach/leds-gpio.h>
 #include <mach/regs-lcd.h>
 #include <plat/regs-serial.h>
@@ -325,8 +324,9 @@ static void __init qt2410_machine_init(void)
        }
        s3c24xx_fb_set_platdata(&qt2410_fb_info);
 
-       s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
-       s3c2410_gpio_setpin(S3C2410_GPB(0), 1);
+       /* set initial state of the LED GPIO */
+       WARN_ON(gpio_request_one(S3C2410_GPB(0), GPIOF_OUT_INIT_HIGH, NULL));
+       gpio_free(S3C2410_GPB(0));
 
        s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
        s3c_i2c0_set_platdata(NULL);
index a6762aae4727f0289724ac1746aa2b3adaf63a7b..7ee73f27f207db87456f904405e61e16c4fceb0e 100644 (file)
@@ -42,7 +42,6 @@
 #include <asm/mach-types.h>
 
 #include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
 #include <mach/regs-lcd.h>
 #include <mach/h1940.h>
 #include <mach/fb.h>
index 03f706dd6009a2f21b5910991c4e228351529ba7..949ae05e07c5c8ff103c6d053da9c650bccbfe96 100644 (file)
@@ -77,8 +77,10 @@ static void s3c2410_pm_prepare(void)
                __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
        }
 
-       if ( machine_is_aml_m5900() )
-               s3c2410_gpio_setpin(S3C2410_GPF(2), 1);
+       if (machine_is_aml_m5900()) {
+               gpio_request_one(S3C2410_GPF(2), GPIOF_OUT_INIT_HIGH, NULL);
+               gpio_free(S3C2410_GPF(2));
+       }
 
        if (machine_is_rx1950()) {
                /* According to S3C2442 user's manual, page 7-17,
@@ -103,8 +105,10 @@ static void s3c2410_pm_resume(void)
        tmp &= S3C2410_GSTATUS2_OFFRESET;
        __raw_writel(tmp, S3C2410_GSTATUS2);
 
-       if ( machine_is_aml_m5900() )
-               s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
+       if (machine_is_aml_m5900()) {
+               gpio_request_one(S3C2410_GPF(2), GPIOF_OUT_INIT_LOW, NULL);
+               gpio_free(S3C2410_GPF(2));
+       }
 }
 
 struct syscore_ops s3c2410_pm_syscore_ops = {
index d04588506ec401a99f7eddae63b2d1932d47d47c..c60f67a75afff8ba291d712091a744696e64893c 100644 (file)
@@ -26,7 +26,6 @@
 #include <asm/irq.h>
 
 #include <mach/regs-power.h>
-#include <mach/regs-gpioj.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-dsc.h>
 
index d4bc7f960bbbe2fa047696258979f2c69190b73a..6c5f4031ff0cba6adc8ba68c3ed660970a75e989 100644 (file)
@@ -39,7 +39,6 @@
 #include <plat/regs-serial.h>
 #include <mach/regs-power.h>
 #include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
 #include <mach/regs-dsc.h>
 #include <plat/regs-spi.h>
 #include <mach/regs-s3c2412.h>
index 6f74118f60c60f66ffbd46f6f0c72821ea2bbc4d..b0b60a1154d68d6e2df2216ca2aa65b6f91dd927 100644 (file)
@@ -36,7 +36,6 @@
 #include <mach/regs-clock.h>
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <mach/regs-gpioj.h>
 #include <mach/regs-dsc.h>
 
 #include <plat/s3c2410.h>
index 5712c85f39b1f2f83ea18dea8bc3857d94dd727a..3d47e023ce942a6de1147e4dcf7f381443a08a63 100644 (file)
 #include <linux/platform_device.h>
 
 #include <plat/gpio-cfg.h>
-#include <plat/s3c64xx-spi.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-gpio.h>
 
 #ifdef CONFIG_S3C64XX_DEV_SPI0
-struct s3c64xx_spi_info s3c64xx_spi0_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 13,
-       .tx_st_done     = 21,
-       .high_speed     = 1,
-};
-
-int s3c64xx_spi0_cfg_gpio(struct platform_device *pdev)
+int s3c64xx_spi0_cfg_gpio(void)
 {
        /* enable hsspi bit in misccr */
        s3c2410_modify_misccr(S3C2416_MISCCR_HSSPI_EN2, 1);
index ed26386636759ebf28f483ed266e34923d2df45e..4e11affce3a88a37997d1d98b3dc1012ffe45423 100644 (file)
@@ -16,7 +16,6 @@
 struct platform_device; /* don't need the contents */
 
 #include <mach/hardware.h>
-#include <mach/regs-gpio.h>
 
 /**
  * s3c24xx_ts_cfg_gpio - configure gpio for s3c2410 systems
@@ -27,8 +26,5 @@ struct platform_device; /* don't need the contents */
  */
 void s3c24xx_ts_cfg_gpio(struct platform_device *dev)
 {
-       s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
-       s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
-       s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
-       s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
+       s3c_gpio_cfgpin_range(S3C2410_GPG(12), 4, S3C_GPIO_SFN(3));
 }
index 52f079a691cb4627b66eb6fa4bb7ad2d14327e9a..28041e83dc823c3d437d2a0ad863adf65f339be5 100644 (file)
@@ -178,13 +178,13 @@ static struct clk init_clocks_off[] = {
                .ctrlbit        = S3C_CLKCON_PCLK_KEYPAD,
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s3c6410-spi.0",
                .parent         = &clk_p,
                .enable         = s3c64xx_pclk_ctrl,
                .ctrlbit        = S3C_CLKCON_PCLK_SPI0,
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s3c6410-spi.1",
                .parent         = &clk_p,
                .enable         = s3c64xx_pclk_ctrl,
                .ctrlbit        = S3C_CLKCON_PCLK_SPI1,
@@ -331,7 +331,7 @@ static struct clk init_clocks_off[] = {
 
 static struct clk clk_48m_spi0 = {
        .name           = "spi_48m",
-       .devname        = "s3c64xx-spi.0",
+       .devname        = "s3c6410-spi.0",
        .parent         = &clk_48m,
        .enable         = s3c64xx_sclk_ctrl,
        .ctrlbit        = S3C_CLKCON_SCLK_SPI0_48,
@@ -339,7 +339,7 @@ static struct clk clk_48m_spi0 = {
 
 static struct clk clk_48m_spi1 = {
        .name           = "spi_48m",
-       .devname        = "s3c64xx-spi.1",
+       .devname        = "s3c6410-spi.1",
        .parent         = &clk_48m,
        .enable         = s3c64xx_sclk_ctrl,
        .ctrlbit        = S3C_CLKCON_SCLK_SPI1_48,
@@ -802,7 +802,7 @@ static struct clksrc_clk clk_sclk_mmc2 = {
 static struct clksrc_clk clk_sclk_spi0 = {
        .clk    = {
                .name           = "spi-bus",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s3c6410-spi.0",
                .ctrlbit        = S3C_CLKCON_SCLK_SPI0,
                .enable         = s3c64xx_sclk_ctrl,
        },
@@ -814,7 +814,7 @@ static struct clksrc_clk clk_sclk_spi0 = {
 static struct clksrc_clk clk_sclk_spi1 = {
        .clk    = {
                .name           = "spi-bus",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s3c6410-spi.1",
                .ctrlbit        = S3C_CLKCON_SCLK_SPI1,
                .enable         = s3c64xx_sclk_ctrl,
        },
@@ -858,10 +858,10 @@ static struct clk_lookup s3c64xx_clk_lookup[] = {
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
        CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
        CLKDEV_INIT(NULL, "spi_busclk0", &clk_p),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk2", &clk_48m_spi0),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk2", &clk_48m_spi1),
+       CLKDEV_INIT("s3c6410-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
+       CLKDEV_INIT("s3c6410-spi.0", "spi_busclk2", &clk_48m_spi0),
+       CLKDEV_INIT("s3c6410-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
+       CLKDEV_INIT("s3c6410-spi.1", "spi_busclk2", &clk_48m_spi1),
 };
 
 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
index fe1a98cf0e4c7cb3a63311efec61f507e9ebf8e2..57b1ff4b2d7ce6417cb113770e9a642230f558bc 100644 (file)
@@ -21,6 +21,7 @@
  */
 enum dma_ch {
        /* DMA0/SDMA0 */
+       DMACH_DT_PROP = -1, /* not yet supported, do not use */
        DMACH_UART0 = 0,
        DMACH_UART0_SRC2,
        DMACH_UART1,
diff --git a/arch/arm/mach-s3c64xx/include/mach/spi-clocks.h b/arch/arm/mach-s3c64xx/include/mach/spi-clocks.h
deleted file mode 100644 (file)
index 9d0c43b..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* linux/arch/arm/mach-s3c64xx/include/mach/spi-clocks.h
- *
- * Copyright (C) 2009 Samsung Electronics Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S3C64XX_PLAT_SPI_CLKS_H
-#define __S3C64XX_PLAT_SPI_CLKS_H __FILE__
-
-#define S3C64XX_SPI_SRCCLK_PCLK                0
-#define S3C64XX_SPI_SRCCLK_SPIBUS      1
-#define S3C64XX_SPI_SRCCLK_48M         2
-
-#endif /* __S3C64XX_PLAT_SPI_CLKS_H */
index d0c352d861f8f341fd93ac2da561b7c2bab35805..6dd4fae33a8236e98e5950a4bdffb7e51afbe12f 100644 (file)
@@ -799,7 +799,7 @@ static void __init crag6410_machine_init(void)
        i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
 
        samsung_keypad_set_platdata(&crag6410_keypad_data);
-       s3c64xx_spi0_set_platdata(&s3c64xx_spi0_pdata, 0, 1);
+       s3c64xx_spi0_set_platdata(NULL, 0, 1);
 
        platform_add_devices(crag6410_devices, ARRAY_SIZE(crag6410_devices));
 
index d9592ad7a82553c56355e4c9474fe839bf4d8e52..4dc53450d71547f3ea4137092354682006a16962 100644 (file)
@@ -9,19 +9,10 @@
  */
 
 #include <linux/gpio.h>
-#include <linux/platform_device.h>
-
 #include <plat/gpio-cfg.h>
-#include <plat/s3c64xx-spi.h>
 
 #ifdef CONFIG_S3C64XX_DEV_SPI0
-struct s3c64xx_spi_info s3c64xx_spi0_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 13,
-       .tx_st_done     = 21,
-};
-
-int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi0_cfg_gpio(void)
 {
        s3c_gpio_cfgall_range(S3C64XX_GPC(0), 3,
                                S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
@@ -30,13 +21,7 @@ int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
 #endif
 
 #ifdef CONFIG_S3C64XX_DEV_SPI1
-struct s3c64xx_spi_info s3c64xx_spi1_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 13,
-       .tx_st_done     = 21,
-};
-
-int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi1_cfg_gpio(void)
 {
        s3c_gpio_cfgall_range(S3C64XX_GPC(4), 3,
                                S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
index ee1e8e7f563142b8775b1b2001f502ccd20ba540..000445596ec4ff5a3577e0d034e40c3574a882ae 100644 (file)
@@ -227,13 +227,13 @@ static struct clk init_clocks_off[] = {
                .ctrlbit        = (1 << 17),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5p64x0-spi.0",
                .parent         = &clk_pclk_low.clk,
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 21),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5p64x0-spi.1",
                .parent         = &clk_pclk_low.clk,
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 22),
@@ -467,7 +467,7 @@ static struct clksrc_clk clk_sclk_uclk = {
 static struct clksrc_clk clk_sclk_spi0 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5p64x0-spi.0",
                .ctrlbit        = (1 << 20),
                .enable         = s5p64x0_sclk_ctrl,
        },
@@ -479,7 +479,7 @@ static struct clksrc_clk clk_sclk_spi0 = {
 static struct clksrc_clk clk_sclk_spi1 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5p64x0-spi.1",
                .ctrlbit        = (1 << 21),
                .enable         = s5p64x0_sclk_ctrl,
        },
@@ -519,8 +519,8 @@ static struct clk_lookup s5p6440_clk_lookup[] = {
        CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_pclk_low.clk),
        CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_sclk_uclk.clk),
        CLKDEV_INIT(NULL, "spi_busclk0", &clk_p),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
+       CLKDEV_INIT("s5p64x0-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
+       CLKDEV_INIT("s5p64x0-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
        CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
        CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
index dae6a13f43bb4dd7eac1425aa01a54e4390f42a8..f3e0ef3d27c9f3d3ba60cc5d053066b0e3af1092 100644 (file)
@@ -236,13 +236,13 @@ static struct clk init_clocks_off[] = {
                .ctrlbit        = (1 << 17),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5p64x0-spi.0",
                .parent         = &clk_pclk_low.clk,
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 21),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5p64x0-spi.1",
                .parent         = &clk_pclk_low.clk,
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 22),
@@ -528,7 +528,7 @@ static struct clksrc_clk clk_sclk_uclk = {
 static struct clksrc_clk clk_sclk_spi0 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5p64x0-spi.0",
                .ctrlbit        = (1 << 20),
                .enable         = s5p64x0_sclk_ctrl,
        },
@@ -540,7 +540,7 @@ static struct clksrc_clk clk_sclk_spi0 = {
 static struct clksrc_clk clk_sclk_spi1 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5p64x0-spi.1",
                .ctrlbit        = (1 << 21),
                .enable         = s5p64x0_sclk_ctrl,
        },
@@ -562,8 +562,8 @@ static struct clk_lookup s5p6450_clk_lookup[] = {
        CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_pclk_low.clk),
        CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_sclk_uclk.clk),
        CLKDEV_INIT(NULL, "spi_busclk0", &clk_p),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
+       CLKDEV_INIT("s5p64x0-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
+       CLKDEV_INIT("s5p64x0-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
        CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
        CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
index 2ee5dc069b3754de7fdb922048a99c3d9156ee74..9c4ce085f5857a3e31e73f31059e29c38998a180 100644 (file)
@@ -36,8 +36,6 @@
 #include <plat/devs.h>
 #include <plat/irqs.h>
 
-static u64 dma_dmamask = DMA_BIT_MASK(32);
-
 static u8 s5p6440_pdma_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
diff --git a/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h b/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
deleted file mode 100644 (file)
index 170a20a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SPI_CLKS_H
-#define __ASM_ARCH_SPI_CLKS_H __FILE__
-
-#define S5P64X0_SPI_SRCCLK_PCLK                0
-#define S5P64X0_SPI_SRCCLK_SCLK                1
-
-#endif /* __ASM_ARCH_SPI_CLKS_H */
index e9b841240352d229f39557a2301bd71bae7df6a2..7664356720ca625ebd2022761dbf22f1f1069306 100644 (file)
@@ -9,21 +9,10 @@
  */
 
 #include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
 #include <plat/gpio-cfg.h>
-#include <plat/cpu.h>
-#include <plat/s3c64xx-spi.h>
 
 #ifdef CONFIG_S3C64XX_DEV_SPI0
-struct s3c64xx_spi_info s3c64xx_spi0_pdata __initdata = {
-       .fifo_lvl_mask  = 0x1ff,
-       .rx_lvl_offset  = 15,
-       .tx_st_done     = 25,
-};
-
-int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi0_cfg_gpio(void)
 {
        if (soc_is_s5p6450())
                s3c_gpio_cfgall_range(S5P6450_GPC(0), 3,
@@ -36,13 +25,7 @@ int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
 #endif
 
 #ifdef CONFIG_S3C64XX_DEV_SPI1
-struct s3c64xx_spi_info s3c64xx_spi1_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 15,
-       .tx_st_done     = 25,
-};
-
-int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi1_cfg_gpio(void)
 {
        if (soc_is_s5p6450())
                s3c_gpio_cfgall_range(S5P6450_GPC(4), 3,
index 16eca4ea201066b6498a503e1f53b1d4c0d7efd0..926219791f0dcd1bbaba3b49f5b690f89ab70975 100644 (file)
@@ -564,19 +564,19 @@ static struct clk init_clocks_off[] = {
                .ctrlbit        = (1 << 5),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5pc100-spi.0",
                .parent         = &clk_div_d1_bus.clk,
                .enable         = s5pc100_d1_4_ctrl,
                .ctrlbit        = (1 << 6),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5pc100-spi.1",
                .parent         = &clk_div_d1_bus.clk,
                .enable         = s5pc100_d1_4_ctrl,
                .ctrlbit        = (1 << 7),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.2",
+               .devname        = "s5pc100-spi.2",
                .parent         = &clk_div_d1_bus.clk,
                .enable         = s5pc100_d1_4_ctrl,
                .ctrlbit        = (1 << 8),
@@ -702,7 +702,7 @@ static struct clk clk_hsmmc0 = {
 
 static struct clk clk_48m_spi0 = {
        .name           = "spi_48m",
-       .devname        = "s3c64xx-spi.0",
+       .devname        = "s5pc100-spi.0",
        .parent         = &clk_mout_48m.clk,
        .enable         = s5pc100_sclk0_ctrl,
        .ctrlbit        = (1 << 7),
@@ -710,7 +710,7 @@ static struct clk clk_48m_spi0 = {
 
 static struct clk clk_48m_spi1 = {
        .name           = "spi_48m",
-       .devname        = "s3c64xx-spi.1",
+       .devname        = "s5pc100-spi.1",
        .parent         = &clk_mout_48m.clk,
        .enable         = s5pc100_sclk0_ctrl,
        .ctrlbit        = (1 << 8),
@@ -718,7 +718,7 @@ static struct clk clk_48m_spi1 = {
 
 static struct clk clk_48m_spi2 = {
        .name           = "spi_48m",
-       .devname        = "s3c64xx-spi.2",
+       .devname        = "s5pc100-spi.2",
        .parent         = &clk_mout_48m.clk,
        .enable         = s5pc100_sclk0_ctrl,
        .ctrlbit        = (1 << 9),
@@ -1085,7 +1085,7 @@ static struct clksrc_clk clk_sclk_mmc2 = {
 static struct clksrc_clk clk_sclk_spi0 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5pc100-spi.0",
                .ctrlbit        = (1 << 4),
                .enable         = s5pc100_sclk0_ctrl,
        },
@@ -1097,7 +1097,7 @@ static struct clksrc_clk clk_sclk_spi0 = {
 static struct clksrc_clk clk_sclk_spi1 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5pc100-spi.1",
                .ctrlbit        = (1 << 5),
                .enable         = s5pc100_sclk0_ctrl,
        },
@@ -1109,7 +1109,7 @@ static struct clksrc_clk clk_sclk_spi1 = {
 static struct clksrc_clk clk_sclk_spi2 = {
        .clk    = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.2",
+               .devname        = "s5pc100-spi.2",
                .ctrlbit        = (1 << 6),
                .enable         = s5pc100_sclk0_ctrl,
        },
@@ -1315,12 +1315,12 @@ static struct clk_lookup s5pc100_clk_lookup[] = {
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
        CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
        CLKDEV_INIT(NULL, "spi_busclk0", &clk_p),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk1", &clk_48m_spi0),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk2", &clk_sclk_spi0.clk),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk1", &clk_48m_spi1),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk2", &clk_sclk_spi1.clk),
-       CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk1", &clk_48m_spi2),
-       CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk2", &clk_sclk_spi2.clk),
+       CLKDEV_INIT("s5pc100-spi.0", "spi_busclk1", &clk_48m_spi0),
+       CLKDEV_INIT("s5pc100-spi.0", "spi_busclk2", &clk_sclk_spi0.clk),
+       CLKDEV_INIT("s5pc100-spi.1", "spi_busclk1", &clk_48m_spi1),
+       CLKDEV_INIT("s5pc100-spi.1", "spi_busclk2", &clk_sclk_spi1.clk),
+       CLKDEV_INIT("s5pc100-spi.2", "spi_busclk1", &clk_48m_spi2),
+       CLKDEV_INIT("s5pc100-spi.2", "spi_busclk2", &clk_sclk_spi2.clk),
 };
 
 void __init s5pc100_register_clocks(void)
index afd8db2d599155720f0a8b1fafc7bec7a539bde8..b1418409709e531cc3ed47d2d971a0ace6940da4 100644 (file)
@@ -33,8 +33,6 @@
 #include <mach/irqs.h>
 #include <mach/dma.h>
 
-static u64 dma_dmamask = DMA_BIT_MASK(32);
-
 static u8 pdma0_peri[] = {
        DMACH_UART0_RX,
        DMACH_UART0_TX,
diff --git a/arch/arm/mach-s5pc100/include/mach/spi-clocks.h b/arch/arm/mach-s5pc100/include/mach/spi-clocks.h
deleted file mode 100644 (file)
index 65e4263..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* linux/arch/arm/mach-s5pc100/include/mach/spi-clocks.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S5PC100_PLAT_SPI_CLKS_H
-#define __S5PC100_PLAT_SPI_CLKS_H __FILE__
-
-#define S5PC100_SPI_SRCCLK_PCLK                0
-#define S5PC100_SPI_SRCCLK_48M         1
-#define S5PC100_SPI_SRCCLK_SPIBUS      2
-
-#endif /* __S5PC100_PLAT_SPI_CLKS_H */
index 431a6f747caa196844c3f3bcb5559a0c3c33dac9..183567961de1c32a842674b0b3812168785d1908 100644 (file)
@@ -9,20 +9,10 @@
  */
 
 #include <linux/gpio.h>
-#include <linux/platform_device.h>
-
 #include <plat/gpio-cfg.h>
-#include <plat/s3c64xx-spi.h>
 
 #ifdef CONFIG_S3C64XX_DEV_SPI0
-struct s3c64xx_spi_info s3c64xx_spi0_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 13,
-       .high_speed     = 1,
-       .tx_st_done     = 21,
-};
-
-int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi0_cfg_gpio(void)
 {
        s3c_gpio_cfgall_range(S5PC100_GPB(0), 3,
                                S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
@@ -31,14 +21,7 @@ int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
 #endif
 
 #ifdef CONFIG_S3C64XX_DEV_SPI1
-struct s3c64xx_spi_info s3c64xx_spi1_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 13,
-       .high_speed     = 1,
-       .tx_st_done     = 21,
-};
-
-int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi1_cfg_gpio(void)
 {
        s3c_gpio_cfgall_range(S5PC100_GPB(4), 3,
                                S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
@@ -47,14 +30,7 @@ int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
 #endif
 
 #ifdef CONFIG_S3C64XX_DEV_SPI2
-struct s3c64xx_spi_info s3c64xx_spi2_pdata __initdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 13,
-       .high_speed     = 1,
-       .tx_st_done     = 21,
-};
-
-int s3c64xx_spi2_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi2_cfg_gpio(void)
 {
        s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(3));
        s3c_gpio_setpull(S5PC100_GPG3(0), S3C_GPIO_PULL_UP);
index 09609d50961d491c09f0f2e8926453e3db7cd0ce..fcdf52dbcc49f9bb8525790bc77953db7f452b73 100644 (file)
@@ -445,19 +445,19 @@ static struct clk init_clocks_off[] = {
                .ctrlbit        = (1 << 11),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5pv210-spi.0",
                .parent         = &clk_pclk_psys.clk,
                .enable         = s5pv210_clk_ip3_ctrl,
                .ctrlbit        = (1<<12),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5pv210-spi.1",
                .parent         = &clk_pclk_psys.clk,
                .enable         = s5pv210_clk_ip3_ctrl,
                .ctrlbit        = (1<<13),
        }, {
                .name           = "spi",
-               .devname        = "s3c64xx-spi.2",
+               .devname        = "s5pv210-spi.2",
                .parent         = &clk_pclk_psys.clk,
                .enable         = s5pv210_clk_ip3_ctrl,
                .ctrlbit        = (1<<14),
@@ -1035,7 +1035,7 @@ static struct clksrc_clk clk_sclk_mmc3 = {
 static struct clksrc_clk clk_sclk_spi0 = {
        .clk            = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.0",
+               .devname        = "s5pv210-spi.0",
                .enable         = s5pv210_clk_mask0_ctrl,
                .ctrlbit        = (1 << 16),
        },
@@ -1047,7 +1047,7 @@ static struct clksrc_clk clk_sclk_spi0 = {
 static struct clksrc_clk clk_sclk_spi1 = {
        .clk            = {
                .name           = "sclk_spi",
-               .devname        = "s3c64xx-spi.1",
+               .devname        = "s5pv210-spi.1",
                .enable         = s5pv210_clk_mask0_ctrl,
                .ctrlbit        = (1 << 17),
        },
@@ -1331,8 +1331,8 @@ static struct clk_lookup s5pv210_clk_lookup[] = {
        CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
        CLKDEV_INIT("s3c-sdhci.3", "mmc_busclk.2", &clk_sclk_mmc3.clk),
        CLKDEV_INIT(NULL, "spi_busclk0", &clk_p),
-       CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
-       CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
+       CLKDEV_INIT("s5pv210-spi.0", "spi_busclk1", &clk_sclk_spi0.clk),
+       CLKDEV_INIT("s5pv210-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
 };
 
 void __init s5pv210_register_clocks(void)
diff --git a/arch/arm/mach-s5pv210/include/mach/spi-clocks.h b/arch/arm/mach-s5pv210/include/mach/spi-clocks.h
deleted file mode 100644 (file)
index 02acded..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/spi-clocks.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S5PV210_PLAT_SPI_CLKS_H
-#define __S5PV210_PLAT_SPI_CLKS_H __FILE__
-
-#define S5PV210_SPI_SRCCLK_PCLK                0
-#define S5PV210_SPI_SRCCLK_SCLK                1
-
-#endif /* __S5PV210_PLAT_SPI_CLKS_H */
index f43c5048a37d0f5038b1be3c872b159be6ac5448..81aecc162f8220991e4e7d4452912758f29ea446 100644 (file)
@@ -9,20 +9,10 @@
  */
 
 #include <linux/gpio.h>
-#include <linux/platform_device.h>
-
 #include <plat/gpio-cfg.h>
-#include <plat/s3c64xx-spi.h>
 
 #ifdef CONFIG_S3C64XX_DEV_SPI0
-struct s3c64xx_spi_info s3c64xx_spi0_pdata = {
-       .fifo_lvl_mask  = 0x1ff,
-       .rx_lvl_offset  = 15,
-       .high_speed     = 1,
-       .tx_st_done     = 25,
-};
-
-int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi0_cfg_gpio(void)
 {
        s3c_gpio_cfgpin(S5PV210_GPB(0), S3C_GPIO_SFN(2));
        s3c_gpio_setpull(S5PV210_GPB(0), S3C_GPIO_PULL_UP);
@@ -33,14 +23,7 @@ int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
 #endif
 
 #ifdef CONFIG_S3C64XX_DEV_SPI1
-struct s3c64xx_spi_info s3c64xx_spi1_pdata = {
-       .fifo_lvl_mask  = 0x7f,
-       .rx_lvl_offset  = 15,
-       .high_speed     = 1,
-       .tx_st_done     = 25,
-};
-
-int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
+int s3c64xx_spi1_cfg_gpio(void)
 {
        s3c_gpio_cfgpin(S5PV210_GPB(4), S3C_GPIO_SFN(2));
        s3c_gpio_setpull(S5PV210_GPB(4), S3C_GPIO_PULL_UP);
index e859fcdb3d58cf7e9d31db02bdecc332ac380125..fde0d23121dc6e14acd614504d054d0c83f778c6 100644 (file)
 #include <mach/common.h>
 #include <mach/emev2.h>
 
+#ifdef CONFIG_ARCH_SH73A0
 #define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \
                        of_machine_is_compatible("renesas,sh73a0"))
+#else
+#define is_sh73a0() (0)
+#endif
+
 #define is_r8a7779() machine_is_marzen()
 
 #ifdef CONFIG_ARCH_EMEV2
index 0f41bd1c47c3a82353392aa8925c76a5ef6663cc..66db5f13af844360b1b5845d1b06c13a6d51445a 100644 (file)
@@ -87,7 +87,7 @@ void __init spear3xx_map_io(void)
 
 static void __init spear3xx_timer_init(void)
 {
-       char pclk_name[] = "pll3_48m_clk";
+       char pclk_name[] = "pll3_clk";
        struct clk *gpt_clk, *pclk;
 
        spear3xx_clk_init();
index 2e2e3596583e9072318dbf895644c5aa67a90e38..9af67d003c62ce6f167307020fcd2f52fa181e8a 100644 (file)
@@ -423,7 +423,7 @@ void __init spear6xx_map_io(void)
 
 static void __init spear6xx_timer_init(void)
 {
-       char pclk_name[] = "pll3_48m_clk";
+       char pclk_name[] = "pll3_clk";
        struct clk *gpt_clk, *pclk;
 
        spear6xx_clk_init();
index 6a113a9bb87a73b17368267715aec791127fcd83..7c407393cd07a60924ad1d19fce890b51ff61547 100644 (file)
@@ -63,7 +63,6 @@ comment "Tegra board type"
 config MACH_HARMONY
        bool "Harmony board"
        depends on ARCH_TEGRA_2x_SOC
-       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for nVidia Harmony development platform
 
@@ -71,7 +70,6 @@ config MACH_KAEN
        bool "Kaen board"
        depends on ARCH_TEGRA_2x_SOC
        select MACH_SEABOARD
-       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for the Kaen version of Seaboard
 
@@ -84,7 +82,6 @@ config MACH_PAZ00
 config MACH_SEABOARD
        bool "Seaboard board"
        depends on ARCH_TEGRA_2x_SOC
-       select MACH_HAS_SND_SOC_TEGRA_WM8903 if SND_SOC
        help
          Support for nVidia Seaboard development platform. It will
         also be included for some of the derivative boards that
index 2eb4445ddb1435648cdba9d587d50fa8c8b7a04a..90aae34245cd32c13e8c5ba6a6d6de409342ee6f 100644 (file)
@@ -8,9 +8,10 @@ obj-y                                   += timer.o
 obj-y                                  += fuse.o
 obj-y                                  += pmc.o
 obj-y                                  += flowctrl.o
+obj-y                                  += powergate.o
+obj-y                                  += apbio.o
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
 obj-$(CONFIG_CPU_IDLE)                 += sleep.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += powergate.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += tegra2_emc.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += board-dt-tegra30.o
@@ -18,7 +19,7 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC)               += tegra30_clocks.o
 obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o
 obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
-obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o apbio.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)                        += pcie.o
 obj-$(CONFIG_USB_SUPPORT)              += usb_phy.o
index 9a82094092d72221e987f603496d93a683da2931..435f00ca3c5843db825b1648c7bc0acdd9961b48 100644 (file)
@@ -2,9 +2,10 @@ zreladdr-$(CONFIG_ARCH_TEGRA_2x_SOC)   += 0x00008000
 params_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00000100
 initrd_phys-$(CONFIG_ARCH_TEGRA_2x_SOC)        := 0x00800000
 
-dtb-$(CONFIG_MACH_HARMONY) += tegra-harmony.dtb
-dtb-$(CONFIG_MACH_PAZ00) += tegra-paz00.dtb
-dtb-$(CONFIG_MACH_SEABOARD) += tegra-seaboard.dtb
-dtb-$(CONFIG_MACH_TRIMSLICE) += tegra-trimslice.dtb
-dtb-$(CONFIG_MACH_VENTANA) += tegra-ventana.dtb
-dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra-cardhu.dtb
+dtb-$(CONFIG_MACH_HARMONY) += tegra20-harmony.dtb
+dtb-$(CONFIG_MACH_PAZ00) += tegra20-paz00.dtb
+dtb-$(CONFIG_MACH_SEABOARD) += tegra20-seaboard.dtb
+dtb-$(CONFIG_MACH_TRIMSLICE) += tegra20-trimslice.dtb
+dtb-$(CONFIG_MACH_VENTANA) += tegra20-ventana.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-whistler.dtb
+dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30-cardhu.dtb
index e75451e517bdd2b55a4c94bc17be3abaddc24c1c..dc0fe389be5645e632a669ee932f50140e43d80c 100644 (file)
@@ -15,6 +15,9 @@
 
 #include <linux/kernel.h>
 #include <linux/io.h>
+#include <mach/iomap.h>
+#include <linux/of.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
 
 #include <mach/dma.h>
-#include <mach/iomap.h>
 
 #include "apbio.h"
 
+#if defined(CONFIG_TEGRA_SYSTEM_DMA) || defined(CONFIG_TEGRA20_APB_DMA)
 static DEFINE_MUTEX(tegra_apb_dma_lock);
-
-static struct tegra_dma_channel *tegra_apb_dma;
 static u32 *tegra_apb_bb;
 static dma_addr_t tegra_apb_bb_phys;
 static DECLARE_COMPLETION(tegra_apb_wait);
 
+static u32 tegra_apb_readl_direct(unsigned long offset);
+static void tegra_apb_writel_direct(u32 value, unsigned long offset);
+
+#if defined(CONFIG_TEGRA_SYSTEM_DMA)
+static struct tegra_dma_channel *tegra_apb_dma;
+
 bool tegra_apb_init(void)
 {
        struct tegra_dma_channel *ch;
@@ -72,13 +79,13 @@ static void apb_dma_complete(struct tegra_dma_req *req)
        complete(&tegra_apb_wait);
 }
 
-u32 tegra_apb_readl(unsigned long offset)
+static u32 tegra_apb_readl_using_dma(unsigned long offset)
 {
        struct tegra_dma_req req;
        int ret;
 
        if (!tegra_apb_dma && !tegra_apb_init())
-               return readl(IO_TO_VIRT(offset));
+               return tegra_apb_readl_direct(offset);
 
        mutex_lock(&tegra_apb_dma_lock);
        req.complete = apb_dma_complete;
@@ -108,13 +115,13 @@ u32 tegra_apb_readl(unsigned long offset)
        return *((u32 *)tegra_apb_bb);
 }
 
-void tegra_apb_writel(u32 value, unsigned long offset)
+static void tegra_apb_writel_using_dma(u32 value, unsigned long offset)
 {
        struct tegra_dma_req req;
        int ret;
 
        if (!tegra_apb_dma && !tegra_apb_init()) {
-               writel(value, IO_TO_VIRT(offset));
+               tegra_apb_writel_direct(value, offset);
                return;
        }
 
@@ -143,3 +150,176 @@ void tegra_apb_writel(u32 value, unsigned long offset)
 
        mutex_unlock(&tegra_apb_dma_lock);
 }
+
+#else
+static struct dma_chan *tegra_apb_dma_chan;
+static struct dma_slave_config dma_sconfig;
+
+bool tegra_apb_dma_init(void)
+{
+       dma_cap_mask_t mask;
+
+       mutex_lock(&tegra_apb_dma_lock);
+
+       /* Check to see if we raced to setup */
+       if (tegra_apb_dma_chan)
+               goto skip_init;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       tegra_apb_dma_chan = dma_request_channel(mask, NULL, NULL);
+       if (!tegra_apb_dma_chan) {
+               /*
+                * This is common until the device is probed, so don't
+                * shout about it.
+                */
+               pr_debug("%s: can not allocate dma channel\n", __func__);
+               goto err_dma_alloc;
+       }
+
+       tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
+               &tegra_apb_bb_phys, GFP_KERNEL);
+       if (!tegra_apb_bb) {
+               pr_err("%s: can not allocate bounce buffer\n", __func__);
+               goto err_buff_alloc;
+       }
+
+       dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       dma_sconfig.slave_id = TEGRA_DMA_REQ_SEL_CNTR;
+       dma_sconfig.src_maxburst = 1;
+       dma_sconfig.dst_maxburst = 1;
+
+skip_init:
+       mutex_unlock(&tegra_apb_dma_lock);
+       return true;
+
+err_buff_alloc:
+       dma_release_channel(tegra_apb_dma_chan);
+       tegra_apb_dma_chan = NULL;
+
+err_dma_alloc:
+       mutex_unlock(&tegra_apb_dma_lock);
+       return false;
+}
+
+static void apb_dma_complete(void *args)
+{
+       complete(&tegra_apb_wait);
+}
+
+static int do_dma_transfer(unsigned long apb_add,
+               enum dma_transfer_direction dir)
+{
+       struct dma_async_tx_descriptor *dma_desc;
+       int ret;
+
+       if (dir == DMA_DEV_TO_MEM)
+               dma_sconfig.src_addr = apb_add;
+       else
+               dma_sconfig.dst_addr = apb_add;
+
+       ret = dmaengine_slave_config(tegra_apb_dma_chan, &dma_sconfig);
+       if (ret)
+               return ret;
+
+       dma_desc = dmaengine_prep_slave_single(tegra_apb_dma_chan,
+                       tegra_apb_bb_phys, sizeof(u32), dir,
+                       DMA_PREP_INTERRUPT |  DMA_CTRL_ACK);
+       if (!dma_desc)
+               return -EINVAL;
+
+       dma_desc->callback = apb_dma_complete;
+       dma_desc->callback_param = NULL;
+
+       INIT_COMPLETION(tegra_apb_wait);
+
+       dmaengine_submit(dma_desc);
+       dma_async_issue_pending(tegra_apb_dma_chan);
+       ret = wait_for_completion_timeout(&tegra_apb_wait,
+               msecs_to_jiffies(50));
+
+       if (WARN(ret == 0, "apb read dma timed out")) {
+               dmaengine_terminate_all(tegra_apb_dma_chan);
+               return -EFAULT;
+       }
+       return 0;
+}
+
+static u32 tegra_apb_readl_using_dma(unsigned long offset)
+{
+       int ret;
+
+       if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
+               return tegra_apb_readl_direct(offset);
+
+       mutex_lock(&tegra_apb_dma_lock);
+       ret = do_dma_transfer(offset, DMA_DEV_TO_MEM);
+       if (ret < 0) {
+               pr_err("error in reading offset 0x%08lx using dma\n", offset);
+               *(u32 *)tegra_apb_bb = 0;
+       }
+       mutex_unlock(&tegra_apb_dma_lock);
+       return *((u32 *)tegra_apb_bb);
+}
+
+static void tegra_apb_writel_using_dma(u32 value, unsigned long offset)
+{
+       int ret;
+
+       if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) {
+               tegra_apb_writel_direct(value, offset);
+               return;
+       }
+
+       mutex_lock(&tegra_apb_dma_lock);
+       *((u32 *)tegra_apb_bb) = value;
+       ret = do_dma_transfer(offset, DMA_MEM_TO_DEV);
+       if (ret < 0)
+               pr_err("error in writing offset 0x%08lx using dma\n", offset);
+       mutex_unlock(&tegra_apb_dma_lock);
+}
+#endif
+#else
+#define tegra_apb_readl_using_dma tegra_apb_readl_direct
+#define tegra_apb_writel_using_dma tegra_apb_writel_direct
+#endif
+
+typedef u32 (*apbio_read_fptr)(unsigned long offset);
+typedef void (*apbio_write_fptr)(u32 value, unsigned long offset);
+
+static apbio_read_fptr apbio_read;
+static apbio_write_fptr apbio_write;
+
+static u32 tegra_apb_readl_direct(unsigned long offset)
+{
+       return readl(IO_TO_VIRT(offset));
+}
+
+static void tegra_apb_writel_direct(u32 value, unsigned long offset)
+{
+       writel(value, IO_TO_VIRT(offset));
+}
+
+void tegra_apb_io_init(void)
+{
+       /* Need to use dma only when it is Tegra20 based platform */
+       if (of_machine_is_compatible("nvidia,tegra20") ||
+                       !of_have_populated_dt()) {
+               apbio_read = tegra_apb_readl_using_dma;
+               apbio_write = tegra_apb_writel_using_dma;
+       } else {
+               apbio_read = tegra_apb_readl_direct;
+               apbio_write = tegra_apb_writel_direct;
+       }
+}
+
+u32 tegra_apb_readl(unsigned long offset)
+{
+       return apbio_read(offset);
+}
+
+void tegra_apb_writel(u32 value, unsigned long offset)
+{
+       apbio_write(value, offset);
+}
index 8b49e8c89a648993ec7452d2550a5552998c03c6..f05d71c303c75979abd43ebb1f079920a156632f 100644 (file)
 #ifndef __MACH_TEGRA_APBIO_H
 #define __MACH_TEGRA_APBIO_H
 
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
-
+void tegra_apb_io_init(void);
 u32 tegra_apb_readl(unsigned long offset);
 void tegra_apb_writel(u32 value, unsigned long offset);
-
-#else
-#include <asm/io.h>
-#include <mach/io.h>
-
-static inline u32 tegra_apb_readl(unsigned long offset)
-{
-        return readl(IO_TO_VIRT(offset));
-}
-
-static inline void tegra_apb_writel(u32 value, unsigned long offset)
-{
-        writel(value, IO_TO_VIRT(offset));
-}
-#endif
-
 #endif
index 204a5c8b0b574bd0cf2b46f5b0d4d1ccde87dd61..96fef6bcc65116bde2071ba6a2c46b66d6a1ed54 100644 (file)
@@ -33,6 +33,7 @@
 #include "clock.h"
 #include "fuse.h"
 #include "pmc.h"
+#include "apbio.h"
 
 /*
  * Storage for debug-macro.S's state.
@@ -127,6 +128,7 @@ static void __init tegra_init_cache(u32 tag_latency, u32 data_latency)
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 void __init tegra20_init_early(void)
 {
+       tegra_apb_io_init();
        tegra_init_fuse();
        tegra2_init_clocks();
        tegra_clk_init_from_table(tegra20_clk_init_table);
@@ -138,6 +140,7 @@ void __init tegra20_init_early(void)
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
 void __init tegra30_init_early(void)
 {
+       tegra_apb_io_init();
        tegra_init_fuse();
        tegra30_init_clocks();
        tegra_clk_init_from_table(tegra30_clk_init_table);
index d83a8c0296f5a2babaf161965aed5d5276fb95df..566e2f88899bdbde99595d4e166a1e87ad47f0aa 100644 (file)
@@ -27,9 +27,9 @@
 #include <linux/cpuidle.h>
 #include <linux/hrtimer.h>
 
-#include <mach/iomap.h>
+#include <asm/proc-fns.h>
 
-extern void tegra_cpu_wfi(void);
+#include <mach/iomap.h>
 
 static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv, int index);
@@ -64,7 +64,7 @@ static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
 
        enter = ktime_get();
 
-       tegra_cpu_wfi();
+       cpu_do_idle();
 
        exit = ktime_sub(ktime_get(), enter);
        us = ktime_to_us(exit);
index 5b20197bae7ffbe334c2f7f1ca6bf3167006832c..d29b156a801123b8d0bdbc60045a89ab06a948b2 100644 (file)
        movw    \reg, #:lower16:\val
        movt    \reg, #:upper16:\val
 .endm
-
-/*
- * tegra_cpu_wfi
- *
- * puts current CPU in clock-gated wfi using the flow controller
- *
- * corrupts r0-r3
- * must be called with MMU on
- */
-
-ENTRY(tegra_cpu_wfi)
-       cpu_id  r0
-       cpu_to_halt_reg r1, r0
-       cpu_to_csr_reg r2, r0
-       mov32   r0, TEGRA_FLOW_CTRL_VIRT
-       mov     r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
-       str     r3, [r0, r2]    @ clear event & interrupt status
-       mov     r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME
-       str     r3, [r0, r1]    @ put flow controller in wait irq mode
-       dsb
-       wfi
-       mov     r3, #0
-       str     r3, [r0, r1]    @ clear flow controller halt status
-       mov     r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
-       str     r3, [r0, r2]    @ clear event & interrupt status
-       dsb
-       mov     pc, lr
-ENDPROC(tegra_cpu_wfi)
-
index 53d3d46dec1290b4265a3c3c26d7ffc0449f223e..c013bbf79cac0d0eff64edfd5221d7815bb04879 100644 (file)
@@ -41,6 +41,7 @@ config MACH_HREFV60
 config MACH_SNOWBALL
        bool "U8500 Snowball platform"
        select MACH_MOP500
+       select LEDS_GPIO
        help
          Include support for the snowball development platform.
 
index 920251cf834cd8859900417cd106d9af7e83a210..18ff781cfbe41a748e4765915292f62f7781540c 100644 (file)
@@ -80,7 +80,7 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
 };
 #endif
 
-static struct mmci_platform_data mop500_sdi0_data = {
+struct mmci_platform_data mop500_sdi0_data = {
        .ios_handler    = mop500_sdi0_ios_handler,
        .ocr_mask       = MMC_VDD_29_30,
        .f_max          = 50000000,
@@ -227,7 +227,7 @@ static struct stedma40_chan_cfg mop500_sdi4_dma_cfg_tx = {
 };
 #endif
 
-static struct mmci_platform_data mop500_sdi4_data = {
+struct mmci_platform_data mop500_sdi4_data = {
        .ocr_mask       = MMC_VDD_29_30,
        .f_max          = 50000000,
        .capabilities   = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA |
index 1509a3cb58335246e19ddf7140e58b875b6e4a31..84461fa2a3ba3d44095797ae4899e669afce83bc 100644 (file)
@@ -58,7 +58,7 @@
 static struct gpio_led snowball_led_array[] = {
        {
                .name = "user_led",
-               .default_trigger = "none",
+               .default_trigger = "heartbeat",
                .gpio = 142,
        },
 };
@@ -331,43 +331,12 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
        },
 };
 
-#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm)   \
-static struct nmk_i2c_controller u8500_i2c##id##_data = { \
-       /*                              \
-        * slave data setup time, which is      \
-        * 250 ns,100ns,10ns which is 14,6,2    \
-        * respectively for a 48 Mhz    \
-        * i2c clock                    \
-        */                             \
-       .slsu           = _slsu,        \
-       /* Tx FIFO threshold */         \
-       .tft            = _tft,         \
-       /* Rx FIFO threshold */         \
-       .rft            = _rft,         \
-       /* std. mode operation */       \
-       .clk_freq       = clk,          \
-       /* Slave response timeout(ms) */\
-       .timeout        = t_out,        \
-       .sm             = _sm,          \
-}
-
-/*
- * The board uses 4 i2c controllers, initialize all of
- * them with slave data setup time of 250 ns,
- * Tx & Rx FIFO threshold values as 8 and standard
- * mode of operation
- */
-U8500_I2C_CONTROLLER(0, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
-U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
-U8500_I2C_CONTROLLER(2,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
-U8500_I2C_CONTROLLER(3,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
-
 static void __init mop500_i2c_init(struct device *parent)
 {
-       db8500_add_i2c0(parent, &u8500_i2c0_data);
-       db8500_add_i2c1(parent, &u8500_i2c1_data);
-       db8500_add_i2c2(parent, &u8500_i2c2_data);
-       db8500_add_i2c3(parent, &u8500_i2c3_data);
+       db8500_add_i2c0(parent, NULL);
+       db8500_add_i2c1(parent, NULL);
+       db8500_add_i2c2(parent, NULL);
+       db8500_add_i2c3(parent, NULL);
 }
 
 static struct gpio_keys_button mop500_gpio_keys[] = {
@@ -625,11 +594,6 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
        &ab8500_device,
 };
 
-static struct platform_device *snowball_of_platform_devs[] __initdata = {
-       &snowball_led_dev,
-       &snowball_key_dev,
-};
-
 static void __init mop500_init_machine(void)
 {
        struct device *parent = NULL;
@@ -769,6 +733,11 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_UX500_DT
 
+static struct platform_device *snowball_of_platform_devs[] __initdata = {
+       &snowball_led_dev,
+       &snowball_key_dev,
+};
+
 struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
        /* Requires DMA and call-back bindings. */
        OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat),
@@ -776,6 +745,8 @@ struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat),
        /* Requires DMA bindings. */
        OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0",  &ssp0_plat),
+       OF_DEV_AUXDATA("arm,pl18x", 0x80126000, "sdi0",  &mop500_sdi0_data),
+       OF_DEV_AUXDATA("arm,pl18x", 0x80114000, "sdi4",  &mop500_sdi4_data),
        /* Requires clock name bindings. */
        OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e000, "gpio.0", NULL),
        OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e080, "gpio.1", NULL),
@@ -786,6 +757,13 @@ struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e000, "gpio.6", NULL),
        OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e080, "gpio.7", NULL),
        OF_DEV_AUXDATA("st,nomadik-gpio", 0xa03fe000, "gpio.8", NULL),
+       OF_DEV_AUXDATA("st,nomadik-i2c", 0x80004000, "nmk-i2c.0", NULL),
+       OF_DEV_AUXDATA("st,nomadik-i2c", 0x80122000, "nmk-i2c.1", NULL),
+       OF_DEV_AUXDATA("st,nomadik-i2c", 0x80128000, "nmk-i2c.2", NULL),
+       OF_DEV_AUXDATA("st,nomadik-i2c", 0x80110000, "nmk-i2c.3", NULL),
+       OF_DEV_AUXDATA("st,nomadik-i2c", 0x8012a000, "nmk-i2c.4", NULL),
+       /* Requires device name bindings. */
+       OF_DEV_AUXDATA("stericsson,nmk_pinctrl", 0, "pinctrl-db8500", NULL),
        {},
 };
 
@@ -818,8 +796,6 @@ static void __init u8500_init_machine(void)
 
        for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
                mop500_platform_devs[i]->dev.parent = parent;
-       for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
-               snowball_platform_devs[i]->dev.parent = parent;
 
        /* automatically probe child nodes of db8500 device */
        of_platform_populate(NULL, u8500_local_bus_nodes, u8500_auxdata_lookup, parent);
@@ -838,18 +814,6 @@ static void __init u8500_init_machine(void)
 
                mop500_uib_init();
 
-       } else if (of_machine_is_compatible("calaosystems,snowball-a9500")) {
-               /*
-                * Devices to be DT:ed:
-                *   snowball_led_dev   = todo
-                *   snowball_key_dev   = todo
-                *   snowball_sbnet_dev = done
-                *   ab8500_device      = done
-                */
-               platform_add_devices(snowball_of_platform_devs,
-                               ARRAY_SIZE(snowball_of_platform_devs));
-
-               snowball_sdi_init(parent);
        } else if (of_machine_is_compatible("st-ericsson,hrefv60+")) {
                /*
                 * The HREFv60 board removed a GPIO expander and routed
@@ -871,7 +835,6 @@ static void __init u8500_init_machine(void)
 
                mop500_uib_init();
        }
-       mop500_i2c_init(parent);
 
        /* This board has full regulator constraints */
        regulator_has_full_constraints();
index 2f87b25a908a31c74264ac0b7a29eb34f85f2c58..b5bfc1a78b1adb0313dd96ff301f7a10f8a842c3 100644 (file)
@@ -9,6 +9,7 @@
 
 /* For NOMADIK_NR_GPIO */
 #include <mach/irqs.h>
+#include <linux/amba/mmci.h>
 
 /* Snowball specific GPIO assignments, this board has no GPIO expander */
 #define SNOWBALL_ACCEL_INT1_GPIO       163
@@ -78,6 +79,8 @@
 
 struct device;
 struct i2c_board_info;
+extern struct mmci_platform_data mop500_sdi0_data;
+extern struct mmci_platform_data mop500_sdi4_data;
 
 extern void mop500_sdi_init(struct device *parent);
 extern void snowball_sdi_init(struct device *parent);
index 33275eb4c6890ab7745bbf0d2b2601ecca5e413f..c8dd94f606dc2d2db89ebf6a3273167d94773d3c 100644 (file)
@@ -139,7 +139,6 @@ static struct platform_device *platform_devs[] __initdata = {
 
 static struct platform_device *of_platform_devs[] __initdata = {
        &u8500_dma40_device,
-       &db8500_pmu_device,
 };
 
 static resource_size_t __initdata db8500_gpio_base[] = {
@@ -237,7 +236,6 @@ struct device * __init u8500_of_init_devices(void)
 
        parent = db8500_soc_device_init();
 
-       db8500_add_rtc(parent);
        db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
 
        platform_device_register_data(parent,
@@ -249,7 +247,7 @@ struct device * __init u8500_of_init_devices(void)
        /*
         * Devices to be DT:ed:
         *   u8500_dma40_device  = todo
-        *   db8500_pmu_device   = todo
+        *   db8500_pmu_device   = done
         *   db8500_prcmu_device = done
         */
        platform_add_devices(of_platform_devs, ARRAY_SIZE(of_platform_devs));
index 741e71feca784134e179a11d0d4389fc80b70a32..66e7f00884ab4b4443d51f56c211ae7ac6385f49 100644 (file)
@@ -63,8 +63,10 @@ static void __init ux500_timer_init(void)
 
        /* TODO: Once MTU has been DT:ed place code above into else. */
        if (of_have_populated_dt()) {
+#ifdef CONFIG_OF
                np = of_find_matching_node(NULL, prcmu_timer_of_match);
                if (!np)
+#endif
                        goto dt_fail;
 
                tmp_base = of_iomap(np, 0);
index bec933b04ef04bebcac7d312b46f710b9ce3a9e3..e95bf84cc837550650ccc053e5afc72486d6682a 100644 (file)
@@ -339,7 +339,6 @@ void __init pci_versatile_preinit(void)
 static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
-       int devslot = PCI_SLOT(dev->devfn);
 
        /* slot,  pin,  irq
         *  24     1     27
index cf8730d35e70bec50ff00d3a35aa4942b1d4d042..fc3730f01650efb674f893f4a78d7077ce015429 100644 (file)
@@ -2,7 +2,8 @@ menu "Versatile Express platform type"
        depends on ARCH_VEXPRESS
 
 config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
-       bool
+       bool "Enable A5 and A9 only errata work-arounds"
+       default y
        select ARM_ERRATA_720789
        select ARM_ERRATA_751472
        select PL310_ERRATA_753970 if CACHE_PL310
@@ -14,7 +15,6 @@ config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
 
 config ARCH_VEXPRESS_CA9X4
        bool "Versatile Express Cortex-A9x4 tile"
-       select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
        select ARM_GIC
        select CPU_V7
        select HAVE_SMP
@@ -22,7 +22,6 @@ config ARCH_VEXPRESS_CA9X4
 
 config ARCH_VEXPRESS_DT
        bool "Device Tree support for Versatile Express platforms"
-       select ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
        select ARM_GIC
        select ARM_PATCH_PHYS_VIRT
        select AUTO_ZRELADDR
index 909f85ebf5f4c2871c17bfa82700238c3f613f04..318d308dfb93993488ab2b3519a8f5089c4c70bc 100644 (file)
@@ -6,4 +6,5 @@ initrd_phys-y   := 0x60800000
 
 dtb-$(CONFIG_ARCH_VEXPRESS_DT) += vexpress-v2p-ca5s.dtb \
                                   vexpress-v2p-ca9.dtb \
-                                  vexpress-v2p-ca15-tc1.dtb
+                                  vexpress-v2p-ca15-tc1.dtb \
+                                  vexpress-v2p-ca15_a7.dtb
index c65cc3b462a5ddef5aad8e4421305c8d22104191..61c492403b05f46957787a7836ef12a0eee44695 100644 (file)
@@ -66,8 +66,15 @@ static void __init ct_ca9x4_init_irq(void)
 
 static void ct_ca9x4_clcd_enable(struct clcd_fb *fb)
 {
-       v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE_DB1, 0);
-       v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE_DB1, 2);
+       u32 site = v2m_get_master_site();
+
+       /*
+        * Old firmware was using the "site" component of the command
+        * to control the DVI muxer (while it should be always 0 ie. MB).
+        * Newer firmware uses the data register. Keep both for compatibility.
+        */
+       v2m_cfg_write(SYS_CFG_MUXFPGA | SYS_CFG_SITE(site), site);
+       v2m_cfg_write(SYS_CFG_DVIMODE | SYS_CFG_SITE(SYS_CFG_SITE_MB), 2);
 }
 
 static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
@@ -105,43 +112,11 @@ static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
 };
 
 
-static long ct_round(struct clk *clk, unsigned long rate)
-{
-       return rate;
-}
-
-static int ct_set(struct clk *clk, unsigned long rate)
-{
-       return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_DB1 | 1, rate);
-}
-
-static const struct clk_ops osc1_clk_ops = {
-       .round  = ct_round,
-       .set    = ct_set,
-};
-
-static struct clk osc1_clk = {
-       .ops    = &osc1_clk_ops,
-       .rate   = 24000000,
-};
-
-static struct clk ct_sp804_clk = {
-       .rate   = 1000000,
-};
-
-static struct clk_lookup lookups[] = {
-       {       /* CLCD */
-               .dev_id         = "ct:clcd",
-               .clk            = &osc1_clk,
-       }, {    /* SP804 timers */
-               .dev_id         = "sp804",
-               .con_id         = "ct-timer0",
-               .clk            = &ct_sp804_clk,
-       }, {    /* SP804 timers */
-               .dev_id         = "sp804",
-               .con_id         = "ct-timer1",
-               .clk            = &ct_sp804_clk,
-       },
+static struct v2m_osc ct_osc1 = {
+       .osc = 1,
+       .rate_min = 10000000,
+       .rate_max = 80000000,
+       .rate_default = 23750000,
 };
 
 static struct resource pmu_resources[] = {
@@ -174,14 +149,10 @@ static struct platform_device pmu_device = {
        .resource       = pmu_resources,
 };
 
-static void __init ct_ca9x4_init_early(void)
-{
-       clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-}
-
 static void __init ct_ca9x4_init(void)
 {
        int i;
+       struct clk *clk;
 
 #ifdef CONFIG_CACHE_L2X0
        void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
@@ -193,6 +164,10 @@ static void __init ct_ca9x4_init(void)
        l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
 #endif
 
+       ct_osc1.site = v2m_get_master_site();
+       clk = v2m_osc_register("ct:osc1", &ct_osc1);
+       clk_register_clkdev(clk, NULL, "ct:clcd");
+
        for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++)
                amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
 
@@ -234,7 +209,6 @@ struct ct_desc ct_ca9x4_desc __initdata = {
        .id             = V2M_CT_ID_CA9,
        .name           = "CA9x4",
        .map_io         = ct_ca9x4_map_io,
-       .init_early     = ct_ca9x4_init_early,
        .init_irq       = ct_ca9x4_init_irq,
        .init_tile      = ct_ca9x4_init,
 #ifdef CONFIG_SMP
diff --git a/arch/arm/mach-vexpress/include/mach/clkdev.h b/arch/arm/mach-vexpress/include/mach/clkdev.h
deleted file mode 100644 (file)
index 3f8307d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __ASM_MACH_CLKDEV_H
-#define __ASM_MACH_CLKDEV_H
-
-#include <plat/clock.h>
-
-struct clk {
-       const struct clk_ops    *ops;
-       unsigned long           rate;
-       const struct icst_params *params;
-};
-
-#define __clk_get(clk) ({ 1; })
-#define __clk_put(clk) do { } while (0)
-
-#endif
index fa8224794e0b75c6a6139d92f0102f5d79d6d829..9f509f55d078c90fb822cad9b44087090f5d2a56 100644 (file)
@@ -18,6 +18,8 @@
 
 #define DEBUG_LL_VIRT_BASE             0xf8000000
 
+#if defined(CONFIG_DEBUG_VEXPRESS_UART0_DETECT)
+
                .macro  addruart,rp,rv,tmp
 
                @ Make an educated guess regarding the memory map:
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
+
+#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_CA9)
+
+               .macro  addruart,rp,rv,tmp
+               mov     \rp, #DEBUG_LL_UART_OFFSET
+               orr     \rv, \rp, #DEBUG_LL_VIRT_BASE
+               orr     \rp, \rp, #DEBUG_LL_PHYS_BASE
+               .endm
+
+#include <asm/hardware/debug-pl01x.S>
+
+#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_RS1)
+
+               .macro  addruart,rp,rv,tmp
+               mov     \rp, #DEBUG_LL_UART_OFFSET_RS1
+               orr     \rv, \rp, #DEBUG_LL_VIRT_BASE
+               orr     \rp, \rp, #DEBUG_LL_PHYS_BASE_RS1
+               .endm
+
+#include <asm/hardware/debug-pl01x.S>
+
+#else /* CONFIG_DEBUG_LL_UART_NONE */
+
+               .macro  addruart, rp, rv, tmp
+               /* Safe dummy values */
+               mov     \rp, #0
+               mov     \rv, #DEBUG_LL_VIRT_BASE
+               .endm
+
+               .macro  senduart,rd,rx
+               .endm
+
+               .macro  waituart,rd,rx
+               .endm
+
+               .macro  busyuart,rd,rx
+               .endm
+
+#endif
index 31a92890893d79385dae0e72ed1a097f8e0f637d..1e388c7bf4d72496dc4d586062d3f8c82753cd5a 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __MACH_MOTHERBOARD_H
 #define __MACH_MOTHERBOARD_H
 
+#include <linux/clk-provider.h>
+
 /*
  * Physical addresses, offset from V2M_PA_CS0-3
  */
 #define SYS_CFG_REBOOT         (9 << 20)
 #define SYS_CFG_DVIMODE                (11 << 20)
 #define SYS_CFG_POWER          (12 << 20)
-#define SYS_CFG_SITE_MB                (0 << 16)
-#define SYS_CFG_SITE_DB1       (1 << 16)
-#define SYS_CFG_SITE_DB2       (2 << 16)
+#define SYS_CFG_SITE(n)                ((n) << 16)
+#define SYS_CFG_SITE_MB                0
+#define SYS_CFG_SITE_DB1       1
+#define SYS_CFG_SITE_DB2       2
 #define SYS_CFG_STACK(n)       ((n) << 12)
 
 #define SYS_CFG_ERR            (1 << 1)
@@ -122,6 +125,8 @@ void v2m_flags_set(u32 data);
 #define SYS_MISC_MASTERSITE    (1 << 14)
 #define SYS_PROCIDx_HBI_MASK   0xfff
 
+int v2m_get_master_site(void);
+
 /*
  * Core tile IDs
  */
@@ -144,4 +149,21 @@ struct ct_desc {
 
 extern struct ct_desc *ct_desc;
 
+/*
+ * OSC clock provider
+ */
+struct v2m_osc {
+       struct clk_hw hw;
+       u8 site; /* 0 = motherboard, 1 = site 1, 2 = site 2 */
+       u8 stack; /* board stack position */
+       u16 osc;
+       unsigned long rate_min;
+       unsigned long rate_max;
+       unsigned long rate_default;
+};
+
+#define to_v2m_osc(osc) container_of(osc, struct v2m_osc, hw)
+
+struct clk *v2m_osc_register(const char *name, struct v2m_osc *osc);
+
 #endif
index 7dab5596b86831936e59053207c9721c7dabbdd1..1e472eb0bbdcc907f725fbba1e13e6f38a43c6f8 100644 (file)
@@ -27,6 +27,7 @@
 
 static unsigned long get_uart_base(void)
 {
+#if defined(CONFIG_DEBUG_VEXPRESS_UART0_DETECT)
        unsigned long mpcore_periph;
 
        /*
@@ -42,6 +43,13 @@ static unsigned long get_uart_base(void)
                return UART_BASE;
        else
                return UART_BASE_RS1;
+#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_CA9)
+       return UART_BASE;
+#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_RS1)
+       return UART_BASE_RS1;
+#else
+       return 0;
+#endif
 }
 
 /*
@@ -51,6 +59,9 @@ static inline void putc(int c)
 {
        unsigned long base = get_uart_base();
 
+       if (!base)
+               return;
+
        while (AMBA_UART_FR(base) & (1 << 5))
                barrier();
 
@@ -61,6 +72,9 @@ static inline void flush(void)
 {
        unsigned long base = get_uart_base();
 
+       if (!base)
+               return;
+
        while (AMBA_UART_FR(base) & (1 << 3))
                barrier();
 }
index fde26adaef32d964a539a12a97f4596af27b1fe1..37608f22ee318a903a79d33ad97678ce71244f23 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/usb/isp1760.h>
 #include <linux/clkdev.h>
+#include <linux/clk-provider.h>
 #include <linux/mtd/physmap.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
 
 #include <asm/arch_timer.h>
 #include <asm/mach-types.h>
@@ -81,16 +84,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
        sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
 }
 
-static void __init v2m_timer_init(void)
-{
-       v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
-       v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
-}
-
-static struct sys_timer v2m_timer = {
-       .init   = v2m_timer_init,
-};
-
 
 static DEFINE_SPINLOCK(v2m_cfg_lock);
 
@@ -147,6 +140,13 @@ void __init v2m_flags_set(u32 data)
        writel(data, v2m_sysreg_base + V2M_SYS_FLAGSSET);
 }
 
+int v2m_get_master_site(void)
+{
+       u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
+
+       return misc & SYS_MISC_MASTERSITE ? SYS_CFG_SITE_DB2 : SYS_CFG_SITE_DB1;
+}
+
 
 static struct resource v2m_pcie_i2c_resource = {
        .start  = V2M_SERIAL_BUS_PCI,
@@ -201,6 +201,11 @@ static struct platform_device v2m_eth_device = {
        .dev.platform_data = &v2m_eth_config,
 };
 
+static struct regulator_consumer_supply v2m_eth_supplies[] = {
+       REGULATOR_SUPPLY("vddvario", "smsc911x"),
+       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
+};
+
 static struct resource v2m_usb_resources[] = {
        {
                .start  = V2M_ISP1761,
@@ -319,98 +324,145 @@ static struct amba_device *v2m_amba_devs[] __initdata = {
 };
 
 
-static long v2m_osc_round(struct clk *clk, unsigned long rate)
+static unsigned long v2m_osc_recalc_rate(struct clk_hw *hw,
+               unsigned long parent_rate)
+{
+       struct v2m_osc *osc = to_v2m_osc(hw);
+
+       return !parent_rate ? osc->rate_default : parent_rate;
+}
+
+static long v2m_osc_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *parent_rate)
 {
+       struct v2m_osc *osc = to_v2m_osc(hw);
+
+       if (WARN_ON(rate < osc->rate_min))
+               rate = osc->rate_min;
+
+       if (WARN_ON(rate > osc->rate_max))
+               rate = osc->rate_max;
+
        return rate;
 }
 
-static int v2m_osc1_set(struct clk *clk, unsigned long rate)
+static int v2m_osc_set_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long parent_rate)
 {
-       return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_MB | 1, rate);
+       struct v2m_osc *osc = to_v2m_osc(hw);
+
+       v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE(osc->site) |
+                       SYS_CFG_STACK(osc->stack) | osc->osc, rate);
+
+       return 0;
 }
 
-static const struct clk_ops osc1_clk_ops = {
-       .round  = v2m_osc_round,
-       .set    = v2m_osc1_set,
-};
-
-static struct clk osc1_clk = {
-       .ops    = &osc1_clk_ops,
-       .rate   = 24000000,
-};
-
-static struct clk osc2_clk = {
-       .rate   = 24000000,
-};
-
-static struct clk v2m_sp804_clk = {
-       .rate   = 1000000,
-};
-
-static struct clk v2m_ref_clk = {
-       .rate   = 32768,
-};
-
-static struct clk dummy_apb_pclk;
-
-static struct clk_lookup v2m_lookups[] = {
-       {       /* AMBA bus clock */
-               .con_id         = "apb_pclk",
-               .clk            = &dummy_apb_pclk,
-       }, {    /* UART0 */
-               .dev_id         = "mb:uart0",
-               .clk            = &osc2_clk,
-       }, {    /* UART1 */
-               .dev_id         = "mb:uart1",
-               .clk            = &osc2_clk,
-       }, {    /* UART2 */
-               .dev_id         = "mb:uart2",
-               .clk            = &osc2_clk,
-       }, {    /* UART3 */
-               .dev_id         = "mb:uart3",
-               .clk            = &osc2_clk,
-       }, {    /* KMI0 */
-               .dev_id         = "mb:kmi0",
-               .clk            = &osc2_clk,
-       }, {    /* KMI1 */
-               .dev_id         = "mb:kmi1",
-               .clk            = &osc2_clk,
-       }, {    /* MMC0 */
-               .dev_id         = "mb:mmci",
-               .clk            = &osc2_clk,
-       }, {    /* CLCD */
-               .dev_id         = "mb:clcd",
-               .clk            = &osc1_clk,
-       }, {    /* SP805 WDT */
-               .dev_id         = "mb:wdt",
-               .clk            = &v2m_ref_clk,
-       }, {    /* SP804 timers */
-               .dev_id         = "sp804",
-               .con_id         = "v2m-timer0",
-               .clk            = &v2m_sp804_clk,
-       }, {    /* SP804 timers */
-               .dev_id         = "sp804",
-               .con_id         = "v2m-timer1",
-               .clk            = &v2m_sp804_clk,
-       },
+static struct clk_ops v2m_osc_ops = {
+       .recalc_rate = v2m_osc_recalc_rate,
+       .round_rate = v2m_osc_round_rate,
+       .set_rate = v2m_osc_set_rate,
+};
+
+struct clk * __init v2m_osc_register(const char *name, struct v2m_osc *osc)
+{
+       struct clk_init_data init;
+
+       WARN_ON(osc->site > 2);
+       WARN_ON(osc->stack > 15);
+       WARN_ON(osc->osc > 4095);
+
+       init.name = name;
+       init.ops = &v2m_osc_ops;
+       init.flags = CLK_IS_ROOT;
+       init.num_parents = 0;
+
+       osc->hw.init = &init;
+
+       return clk_register(NULL, &osc->hw);
+}
+
+static struct v2m_osc v2m_mb_osc1 = {
+       .site = SYS_CFG_SITE_MB,
+       .osc = 1,
+       .rate_min = 23750000,
+       .rate_max = 63500000,
+       .rate_default = 23750000,
+};
+
+static const char *v2m_ref_clk_periphs[] __initconst = {
+       "mb:wdt",   "1000f000.wdt",  "1c0f0000.wdt",    /* SP805 WDT */
+};
+
+static const char *v2m_osc1_periphs[] __initconst = {
+       "mb:clcd",  "1001f000.clcd", "1c1f0000.clcd",   /* PL111 CLCD */
+};
+
+static const char *v2m_osc2_periphs[] __initconst = {
+       "mb:mmci",  "10005000.mmci", "1c050000.mmci",   /* PL180 MMCI */
+       "mb:kmi0",  "10006000.kmi",  "1c060000.kmi",    /* PL050 KMI0 */
+       "mb:kmi1",  "10007000.kmi",  "1c070000.kmi",    /* PL050 KMI1 */
+       "mb:uart0", "10009000.uart", "1c090000.uart",   /* PL011 UART0 */
+       "mb:uart1", "1000a000.uart", "1c0a0000.uart",   /* PL011 UART1 */
+       "mb:uart2", "1000b000.uart", "1c0b0000.uart",   /* PL011 UART2 */
+       "mb:uart3", "1000c000.uart", "1c0c0000.uart",   /* PL011 UART3 */
+};
+
+static void __init v2m_clk_init(void)
+{
+       struct clk *clk;
+       int i;
+
+       clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
+                       CLK_IS_ROOT, 0);
+       WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
+
+       clk = clk_register_fixed_rate(NULL, "mb:ref_clk", NULL,
+                       CLK_IS_ROOT, 32768);
+       for (i = 0; i < ARRAY_SIZE(v2m_ref_clk_periphs); i++)
+               WARN_ON(clk_register_clkdev(clk, NULL, v2m_ref_clk_periphs[i]));
+
+       clk = clk_register_fixed_rate(NULL, "mb:sp804_clk", NULL,
+                       CLK_IS_ROOT, 1000000);
+       WARN_ON(clk_register_clkdev(clk, "v2m-timer0", "sp804"));
+       WARN_ON(clk_register_clkdev(clk, "v2m-timer1", "sp804"));
+
+       clk = v2m_osc_register("mb:osc1", &v2m_mb_osc1);
+       for (i = 0; i < ARRAY_SIZE(v2m_osc1_periphs); i++)
+               WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc1_periphs[i]));
+
+       clk = clk_register_fixed_rate(NULL, "mb:osc2", NULL,
+                       CLK_IS_ROOT, 24000000);
+       for (i = 0; i < ARRAY_SIZE(v2m_osc2_periphs); i++)
+               WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc2_periphs[i]));
+}
+
+static void __init v2m_timer_init(void)
+{
+       v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
+       v2m_clk_init();
+       v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
+}
+
+static struct sys_timer v2m_timer = {
+       .init   = v2m_timer_init,
 };
 
 static void __init v2m_init_early(void)
 {
-       ct_desc->init_early();
-       clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
+       if (ct_desc->init_early)
+               ct_desc->init_early();
        versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
 }
 
 static void v2m_power_off(void)
 {
-       if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE_MB, 0))
+       if (v2m_cfg_write(SYS_CFG_SHUTDOWN | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0))
                printk(KERN_EMERG "Unable to shutdown\n");
 }
 
 static void v2m_restart(char str, const char *cmd)
 {
-       if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE_MB, 0))
+       if (v2m_cfg_write(SYS_CFG_REBOOT | SYS_CFG_SITE(SYS_CFG_SITE_MB), 0))
                printk(KERN_EMERG "Unable to reboot\n");
 }
 
@@ -458,6 +510,9 @@ static void __init v2m_init(void)
 {
        int i;
 
+       regulator_register_fixed(0, v2m_eth_supplies,
+                       ARRAY_SIZE(v2m_eth_supplies));
+
        platform_device_register(&v2m_pcie_i2c_device);
        platform_device_register(&v2m_ddc_i2c_device);
        platform_device_register(&v2m_flash_device);
@@ -522,77 +577,6 @@ void __init v2m_dt_map_io(void)
 #endif
 }
 
-static struct clk_lookup v2m_dt_lookups[] = {
-       {       /* AMBA bus clock */
-               .con_id         = "apb_pclk",
-               .clk            = &dummy_apb_pclk,
-       }, {    /* SP804 timers */
-               .dev_id         = "sp804",
-               .con_id         = "v2m-timer0",
-               .clk            = &v2m_sp804_clk,
-       }, {    /* SP804 timers */
-               .dev_id         = "sp804",
-               .con_id         = "v2m-timer1",
-               .clk            = &v2m_sp804_clk,
-       }, {    /* PL180 MMCI */
-               .dev_id         = "mb:mmci", /* 10005000.mmci */
-               .clk            = &osc2_clk,
-       }, {    /* PL050 KMI0 */
-               .dev_id         = "10006000.kmi",
-               .clk            = &osc2_clk,
-       }, {    /* PL050 KMI1 */
-               .dev_id         = "10007000.kmi",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART0 */
-               .dev_id         = "10009000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART1 */
-               .dev_id         = "1000a000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART2 */
-               .dev_id         = "1000b000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART3 */
-               .dev_id         = "1000c000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* SP805 WDT */
-               .dev_id         = "1000f000.wdt",
-               .clk            = &v2m_ref_clk,
-       }, {    /* PL111 CLCD */
-               .dev_id         = "1001f000.clcd",
-               .clk            = &osc1_clk,
-       },
-       /* RS1 memory map */
-       {       /* PL180 MMCI */
-               .dev_id         = "mb:mmci", /* 1c050000.mmci */
-               .clk            = &osc2_clk,
-       }, {    /* PL050 KMI0 */
-               .dev_id         = "1c060000.kmi",
-               .clk            = &osc2_clk,
-       }, {    /* PL050 KMI1 */
-               .dev_id         = "1c070000.kmi",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART0 */
-               .dev_id         = "1c090000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART1 */
-               .dev_id         = "1c0a0000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART2 */
-               .dev_id         = "1c0b0000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* PL011 UART3 */
-               .dev_id         = "1c0c0000.uart",
-               .clk            = &osc2_clk,
-       }, {    /* SP805 WDT */
-               .dev_id         = "1c0f0000.wdt",
-               .clk            = &v2m_ref_clk,
-       }, {    /* PL111 CLCD */
-               .dev_id         = "1c1f0000.clcd",
-               .clk            = &osc1_clk,
-       },
-};
-
 void __init v2m_dt_init_early(void)
 {
        struct device_node *node;
@@ -605,8 +589,8 @@ void __init v2m_dt_init_early(void)
 
        /* Confirm board type against DT property, if available */
        if (of_property_read_u32(allnodes, "arm,hbi", &dt_hbi) == 0) {
-               u32 misc = readl(v2m_sysreg_base + V2M_SYS_MISC);
-               u32 id = readl(v2m_sysreg_base + (misc & SYS_MISC_MASTERSITE ?
+               int site = v2m_get_master_site();
+               u32 id = readl(v2m_sysreg_base + (site == SYS_CFG_SITE_DB2 ?
                                V2M_SYS_PROCID1 : V2M_SYS_PROCID0));
                u32 hbi = id & SYS_PROCIDx_HBI_MASK;
 
@@ -614,8 +598,6 @@ void __init v2m_dt_init_early(void)
                        pr_warning("vexpress: DT HBI (%x) is not matching "
                                        "hardware (%x)!\n", dt_hbi, hbi);
        }
-
-       clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups));
 }
 
 static  struct of_device_id vexpress_irq_match[] __initdata = {
@@ -637,6 +619,8 @@ static void __init v2m_dt_timer_init(void)
        node = of_find_compatible_node(NULL, NULL, "arm,sp810");
        v2m_sysctl_init(of_iomap(node, 0));
 
+       v2m_clk_init();
+
        err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
        if (WARN_ON(err))
                return;
index 81aedb7c893c24d94814f1c74e32b40cad08e543..54e69973f39b7344ca0e7ccdb01b2a1be696c907 100644 (file)
@@ -1,4 +1,4 @@
-obj-y += devices.o gpio.o irq.o timer.o
+obj-y += devices.o gpio.o irq.o timer.o restart.o
 
 obj-$(CONFIG_VTWM_VERSION_VT8500) += devices-vt8500.o
 obj-$(CONFIG_VTWM_VERSION_WM8505) += devices-wm8505.o
index a464c75844112d8147e07f1ef5cf689e9a969350..f9fbeb2d10e988525c7c775d960f619ec643d6c4 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <mach/restart.h>
 
 #include "devices.h"
 
@@ -62,6 +63,7 @@ void __init bv07_init(void)
        else
                printk(KERN_ERR "PMC Hibernation register could not be remapped, not enabling power off!\n");
 
+       wmt_setup_restart();
        vt8500_set_resources();
        platform_add_devices(devices, ARRAY_SIZE(devices));
        vt8500_gpio_init();
@@ -69,6 +71,7 @@ void __init bv07_init(void)
 
 MACHINE_START(BV07, "Benign BV07 Mini Netbook")
        .atag_offset    = 0x100,
+       .restart        = wmt_restart,
        .reserve        = vt8500_reserve_mem,
        .map_io         = vt8500_map_io,
        .init_irq       = vt8500_init_irq,
diff --git a/arch/arm/mach-vt8500/include/mach/restart.h b/arch/arm/mach-vt8500/include/mach/restart.h
new file mode 100644 (file)
index 0000000..89f9b78
--- /dev/null
@@ -0,0 +1,17 @@
+/* linux/arch/arm/mach-vt8500/restart.h
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+void wmt_setup_restart(void);
+void wmt_restart(char mode, const char *cmd);
diff --git a/arch/arm/mach-vt8500/include/mach/system.h b/arch/arm/mach-vt8500/include/mach/system.h
deleted file mode 100644 (file)
index 58fa801..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-vt8500/include/mach/system.h
- *
- */
-#include <asm/io.h>
-
-/* PM Software Reset request register */
-#define VT8500_PMSR_VIRT       0xf8130060
-
-static inline void arch_reset(char mode, const char *cmd)
-{
-       writel(1, VT8500_PMSR_VIRT);
-}
diff --git a/arch/arm/mach-vt8500/restart.c b/arch/arm/mach-vt8500/restart.c
new file mode 100644 (file)
index 0000000..497e89a
--- /dev/null
@@ -0,0 +1,54 @@
+/* linux/arch/arm/mach-vt8500/restart.c
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <asm/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define LEGACY_PMC_BASE                0xD8130000
+#define WMT_PRIZM_PMSR_REG     0x60
+
+static void __iomem *pmc_base;
+
+void wmt_setup_restart(void)
+{
+       struct device_node *np;
+
+       /*
+        * Check if Power Mgmt Controller node is present in device tree. If no
+        * device tree node, use the legacy PMSR value (valid for all current
+        * SoCs).
+        */
+       np = of_find_compatible_node(NULL, NULL, "wmt,prizm-pmc");
+       if (np) {
+               pmc_base = of_iomap(np, 0);
+
+               if (!pmc_base)
+                       pr_err("%s:of_iomap(pmc) failed\n", __func__);
+
+               of_node_put(np);
+       } else {
+               pmc_base = ioremap(LEGACY_PMC_BASE, 0x1000);
+               if (!pmc_base) {
+                       pr_err("%s:ioremap(rstc) failed\n", __func__);
+                       return;
+               }
+       }
+}
+
+void wmt_restart(char mode, const char *cmd)
+{
+       if (pmc_base)
+               writel(1, pmc_base + WMT_PRIZM_PMSR_REG);
+}
index cf910a956080c56126ee57a34dc7b2ea87fc6295..db19886caf7ce679ff6ac2f98f0d5d70568e2eac 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <mach/restart.h>
 
 #include "devices.h"
 
@@ -61,7 +62,7 @@ void __init wm8505_7in_init(void)
                pm_power_off = &vt8500_power_off;
        else
                printk(KERN_ERR "PMC Hibernation register could not be remapped, not enabling power off!\n");
-
+       wmt_setup_restart();
        wm8505_set_resources();
        platform_add_devices(devices, ARRAY_SIZE(devices));
        vt8500_gpio_init();
@@ -69,6 +70,7 @@ void __init wm8505_7in_init(void)
 
 MACHINE_START(WM8505_7IN_NETBOOK, "WM8505 7-inch generic netbook")
        .atag_offset    = 0x100,
+       .restart        = wmt_restart,
        .reserve        = wm8505_reserve_mem,
        .map_io         = wm8505_map_io,
        .init_irq       = wm8505_init_irq,
index 4044abcf6f9d8d90f3bac55df229267dc09b23ed..655878bcc96d265a2ec81f87112ba48d5b5a037e 100644 (file)
@@ -1091,7 +1091,7 @@ error:
        while (--i)
                if (pages[i])
                        __free_pages(pages[i], 0);
-       if (array_size < PAGE_SIZE)
+       if (array_size <= PAGE_SIZE)
                kfree(pages);
        else
                vfree(pages);
@@ -1106,7 +1106,7 @@ static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t s
        for (i = 0; i < count; i++)
                if (pages[i])
                        __free_pages(pages[i], 0);
-       if (array_size < PAGE_SIZE)
+       if (array_size <= PAGE_SIZE)
                kfree(pages);
        else
                vfree(pages);
index c471436c79522d7722ba08a2baec7223e4c663d5..2e8a1efdf7b85f3443294b396ec5673496dd635d 100644 (file)
@@ -64,7 +64,7 @@ extern void __flush_dcache_page(struct address_space *mapping, struct page *page
 #ifdef CONFIG_ZONE_DMA
 extern phys_addr_t arm_dma_limit;
 #else
-#define arm_dma_limit ((u32)~0)
+#define arm_dma_limit ((phys_addr_t)~0)
 #endif
 
 extern phys_addr_t arm_lowmem_limit;
index e5dad60b558b468315294b2c8b95c70193b6f74d..cf4528d5177448fb79cb5dc6689c873c2dbddb4a 100644 (file)
@@ -791,6 +791,79 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
        }
 }
 
+#ifndef CONFIG_ARM_LPAE
+
+/*
+ * The Linux PMD is made of two consecutive section entries covering 2MB
+ * (see definition in include/asm/pgtable-2level.h).  However a call to
+ * create_mapping() may optimize static mappings by using individual
+ * 1MB section mappings.  This leaves the actual PMD potentially half
+ * initialized if the top or bottom section entry isn't used, leaving it
+ * open to problems if a subsequent ioremap() or vmalloc() tries to use
+ * the virtual space left free by that unused section entry.
+ *
+ * Let's avoid the issue by inserting dummy vm entries covering the unused
+ * PMD halves once the static mappings are in place.
+ */
+
+static void __init pmd_empty_section_gap(unsigned long addr)
+{
+       struct vm_struct *vm;
+
+       vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
+       vm->addr = (void *)addr;
+       vm->size = SECTION_SIZE;
+       vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+       vm->caller = pmd_empty_section_gap;
+       vm_area_add_early(vm);
+}
+
+static void __init fill_pmd_gaps(void)
+{
+       struct vm_struct *vm;
+       unsigned long addr, next = 0;
+       pmd_t *pmd;
+
+       /* we're still single threaded hence no lock needed here */
+       for (vm = vmlist; vm; vm = vm->next) {
+               if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+                       continue;
+               addr = (unsigned long)vm->addr;
+               if (addr < next)
+                       continue;
+
+               /*
+                * Check if this vm starts on an odd section boundary.
+                * If so and the first section entry for this PMD is free
+                * then we block the corresponding virtual address.
+                */
+               if ((addr & ~PMD_MASK) == SECTION_SIZE) {
+                       pmd = pmd_off_k(addr);
+                       if (pmd_none(*pmd))
+                               pmd_empty_section_gap(addr & PMD_MASK);
+               }
+
+               /*
+                * Then check if this vm ends on an odd section boundary.
+                * If so and the second section entry for this PMD is empty
+                * then we block the corresponding virtual address.
+                */
+               addr += vm->size;
+               if ((addr & ~PMD_MASK) == SECTION_SIZE) {
+                       pmd = pmd_off_k(addr) + 1;
+                       if (pmd_none(*pmd))
+                               pmd_empty_section_gap(addr);
+               }
+
+               /* no need to look at any vm entry until we hit the next PMD */
+               next = (addr + PMD_SIZE - 1) & PMD_MASK;
+       }
+}
+
+#else
+#define fill_pmd_gaps() do { } while (0)
+#endif
+
 static void * __initdata vmalloc_min =
        (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
 
@@ -1072,6 +1145,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
         */
        if (mdesc->map_io)
                mdesc->map_io();
+       fill_pmd_gaps();
 
        /*
         * Finally flush the caches and tlb to ensure that we're in a
index 16d0ec4df5f65c7905896bfead4353ba643ebf14..a5c9ad5721c2a1374815cc737ede4c3436dfdba5 100644 (file)
@@ -20,6 +20,11 @@ const struct imx_mxc_rtc_data imx31_mxc_rtc_data __initconst =
        imx_mxc_rtc_data_entry_single(MX31);
 #endif /* ifdef CONFIG_SOC_IMX31 */
 
+#ifdef CONFIG_SOC_IMX35
+const struct imx_mxc_rtc_data imx35_mxc_rtc_data __initconst =
+       imx_mxc_rtc_data_entry_single(MX35);
+#endif /* ifdef CONFIG_SOC_IMX35 */
+
 struct platform_device *__init imx_add_mxc_rtc(
                const struct imx_mxc_rtc_data *data)
 {
index e429ca1b814a179522bdf2bc9bb9e514ac136efc..7cfcc44537f0027e8c2f967a6d6f120ab7f86877 100644 (file)
@@ -67,6 +67,7 @@ extern int mx51_clocks_init(unsigned long ckil, unsigned long osc,
 extern int mx53_clocks_init(unsigned long ckil, unsigned long osc,
                        unsigned long ckih1, unsigned long ckih2);
 extern int mx27_clocks_init_dt(void);
+extern int mx31_clocks_init_dt(void);
 extern int mx51_clocks_init_dt(void);
 extern int mx53_clocks_init_dt(void);
 extern int mx6q_clocks_init(void);
index 36c8989d9de6b993e13dfd8197dcdc95b46df104..2623e7a2e1907368d9d8e7926122199d9892c89c 100644 (file)
 #define MX51_PAD_EIM_D25__UART2_CTS            IOMUX_PAD(0x414, 0x080, 4, __NA_, 0, MX51_UART_PAD_CTRL)
 #define MX51_PAD_EIM_D25__UART3_RXD            IOMUX_PAD(0x414, 0x080, 3, 0x9f4, 0, MX51_UART_PAD_CTRL)
 #define MX51_PAD_EIM_D25__USBOTG_DATA1         IOMUX_PAD(0x414, 0x080, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D25__GPT_CMPOUT1          IOMUX_PAD(0x414, 0x080, 5, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_D26__EIM_D26              IOMUX_PAD(0x418, 0x084, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_D26__KEY_COL7             IOMUX_PAD(0x418, 0x084, 1, 0x9cc, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_D26__UART2_RTS            IOMUX_PAD(0x418, 0x084, 4, 0x9e8, 3, MX51_UART_PAD_CTRL)
 #define MX51_PAD_EIM_D26__UART3_TXD            IOMUX_PAD(0x418, 0x084, 3, __NA_, 0, MX51_UART_PAD_CTRL)
 #define MX51_PAD_EIM_D26__USBOTG_DATA2         IOMUX_PAD(0x418, 0x084, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D26__GPT_CMPOUT2          IOMUX_PAD(0x418, 0x084, 5, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_D27__AUD6_RXC             IOMUX_PAD(0x41c, 0x088, 5, 0x8f4, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_D27__EIM_D27              IOMUX_PAD(0x41c, 0x088, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_D27__GPIO2_9              IOMUX_PAD(0x41c, 0x088, 1, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_EIM_CRE__EIM_CRE              IOMUX_PAD(0x4a0, 0x100, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CRE__GPIO3_2              IOMUX_PAD(0x4a0, 0x100, 1, 0x97c, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_DRAM_CS1__DRAM_CS1            IOMUX_PAD(0x4d0, 0x104, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DRAM_CS1__CCM_CLKO            IOMUX_PAD(0x4d0, 0x104, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_WE_B__GPIO3_3           IOMUX_PAD(0x4e4, 0x108, 3, 0x980, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_WE_B__NANDF_WE_B                IOMUX_PAD(0x4e4, 0x108, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_WE_B__PATA_DIOW         IOMUX_PAD(0x4e4, 0x108, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__GPIO3_9            IOMUX_PAD(0x4fc, 0x120, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__NANDF_RB1          IOMUX_PAD(0x4fc, 0x120, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__PATA_IORDY         IOMUX_PAD(0x4fc, 0x120, 1, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB1__GPT_CMPOUT2                IOMUX_PAD(0x4fc, 0x120, 4, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__SD4_CMD            IOMUX_PAD(0x4fc, 0x120, 0x15, __NA_, 0, MX51_SDHCI_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__DISP2_WAIT         IOMUX_PAD(0x500, 0x124, 5, 0x9a8, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__ECSPI2_SCLK                IOMUX_PAD(0x500, 0x124, 2, __NA_, 0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__FEC_COL            IOMUX_PAD(0x500, 0x124, 1, 0x94c, 0, MX51_PAD_CTRL_2)
 #define MX51_PAD_NANDF_RB2__GPIO3_10           IOMUX_PAD(0x500, 0x124, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__NANDF_RB2          IOMUX_PAD(0x500, 0x124, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__GPT_CMPOUT3                IOMUX_PAD(0x500, 0x124, 4, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__USBH3_H3_DP                IOMUX_PAD(0x500, 0x124, 0x17, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__USBH3_NXT          IOMUX_PAD(0x500, 0x124, 6, 0xa20, 0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB3__DISP1_WAIT         IOMUX_PAD(0x504, 0x128, 5, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT23__DISP2_DAT17      IOMUX_PAD(0x728, 0x328, 5, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT23__DISP2_SER_CS     IOMUX_PAD(0x728, 0x328, 4, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DI1_PIN3__DI1_PIN3            IOMUX_PAD(0x72c, 0x32c, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_DISP_CLK__DI1_DISP_CLK    IOMUX_PAD(0x730, __NA_, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DI1_PIN2__DI1_PIN2            IOMUX_PAD(0x734, 0x330, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN15__DI1_PIN15          IOMUX_PAD(0x738, __NA_, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DI_GP2__DISP1_SER_CLK         IOMUX_PAD(0x740, 0x338, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_DI_GP2__DISP2_WAIT            IOMUX_PAD(0x740, 0x338, 2, 0x9a8, 1, NO_PAD_CTRL)
 #define MX51_PAD_DI_GP3__CSI1_DATA_EN          IOMUX_PAD(0x744, 0x33c, 3, 0x9a0, 1, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_2__PWM1_PWMO            IOMUX_PAD(0x7d4, 0x3cc, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_3__GPIO1_3              IOMUX_PAD(0x7d8, 0x3d0, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_3__I2C2_SDA             IOMUX_PAD(0x7d8, 0x3d0, 0x12, 0x9bc, 3, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_GPIO1_3__CCM_CLKO2            IOMUX_PAD(0x7d8, 0x3d0, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_3__GPT_CLKIN            IOMUX_PAD(0x7d8, 0x3d0, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_3__PLL2_BYP             IOMUX_PAD(0x7d8, 0x3d0, 7, 0x910, 1, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_3__PWM2_PWMO            IOMUX_PAD(0x7d8, 0x3d0, 1, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ    IOMUX_PAD(0x7fc, 0x3d4, 0, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_4__EIM_RDY              IOMUX_PAD(0x804, 0x3d8, 3, 0x938, 1, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_4__GPIO1_4              IOMUX_PAD(0x804, 0x3d8, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_4__WDOG1_WDOG_B         IOMUX_PAD(0x804, 0x3d8, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_4__GPT_CAPIN1           IOMUX_PAD(0x804, 0x3d8, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_5__CSI2_MCLK            IOMUX_PAD(0x808, 0x3dc, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_5__DISP2_PIN16          IOMUX_PAD(0x808, 0x3dc, 3, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_5__GPIO1_5              IOMUX_PAD(0x808, 0x3dc, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_5__WDOG2_WDOG_B         IOMUX_PAD(0x808, 0x3dc, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_5__CCM_CLKO             IOMUX_PAD(0x808, 0x3dc, 5, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_6__DISP2_PIN17          IOMUX_PAD(0x80c, 0x3e0, 4, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_6__GPIO1_6              IOMUX_PAD(0x80c, 0x3e0, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_6__REF_EN_B             IOMUX_PAD(0x80c, 0x3e0, 3, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_6__GPT_CAPIN2           IOMUX_PAD(0x80c, 0x3e0, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_7__CCM_OUT_0            IOMUX_PAD(0x810, 0x3e4, 3, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_7__GPIO1_7              IOMUX_PAD(0x810, 0x3e4, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_7__SD2_WP               IOMUX_PAD(0x810, 0x3e4, 6, __NA_, 0, MX51_ESDHC_PAD_CTRL)
 #define MX51_PAD_GPIO1_8__GPIO1_8              IOMUX_PAD(0x814, 0x3e8, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_8__SD2_CD               IOMUX_PAD(0x814, 0x3e8, 6, __NA_, 0, MX51_ESDHC_PAD_CTRL)
 #define MX51_PAD_GPIO1_8__USBH3_PWR            IOMUX_PAD(0x814, 0x3e8, 1, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_8__CCM_CLKO2            IOMUX_PAD(0x814, 0x3e8, 4, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__CCM_OUT_1            IOMUX_PAD(0x818, 0x3ec, 3, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__DISP2_D1_CS          IOMUX_PAD(0x818, 0x3ec, 2, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__DISP2_SER_CS         IOMUX_PAD(0x818, 0x3ec, 7, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__GPIO1_9              IOMUX_PAD(0x818, 0x3ec, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__SD2_LCTL             IOMUX_PAD(0x818, 0x3ec, 6, __NA_, 0, NO_PAD_CTRL)
 #define MX51_PAD_GPIO1_9__USBH3_OC             IOMUX_PAD(0x818, 0x3ec, 1, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_9__CCM_CLKO             IOMUX_PAD(0x818, 0x3ec, 4, __NA_, 0, NO_PAD_CTRL)
 
 #endif /* __MACH_IOMUX_MX51_H__ */
index 9ffd1bbe615f91fc598268c69be4aa35b2b9dcff..7eb9d13296719a81f9d2bf03622acf1a83add3a1 100644 (file)
 #define MXC_EHCI_INTERFACE_MASK                (0xf)
 
 #define MXC_EHCI_POWER_PINS_ENABLED    (1 << 5)
-#define MXC_EHCI_TTL_ENABLED           (1 << 6)
-
-#define MXC_EHCI_INTERNAL_PHY          (1 << 7)
-#define MXC_EHCI_IPPUE_DOWN            (1 << 8)
-#define MXC_EHCI_IPPUE_UP              (1 << 9)
-#define MXC_EHCI_WAKEUP_ENABLED        (1 << 10)
-#define MXC_EHCI_ITC_NO_THRESHOLD      (1 << 11)
+#define MXC_EHCI_PWR_PIN_ACTIVE_HIGH   (1 << 6)
+#define MXC_EHCI_OC_PIN_ACTIVE_LOW     (1 << 7)
+#define MXC_EHCI_TTL_ENABLED           (1 << 8)
+
+#define MXC_EHCI_INTERNAL_PHY          (1 << 9)
+#define MXC_EHCI_IPPUE_DOWN            (1 << 10)
+#define MXC_EHCI_IPPUE_UP              (1 << 11)
+#define MXC_EHCI_WAKEUP_ENABLED                (1 << 12)
+#define MXC_EHCI_ITC_NO_THRESHOLD      (1 << 13)
 
 #define MXC_USBCTRL_OFFSET             0
 #define MXC_USB_PHY_CTR_FUNC_OFFSET    0x8
index e2d911d16fb48524675175a6de79e05817c5284f..68b180edcfffd0e05c9256aaa153993500177f84 100644 (file)
@@ -243,9 +243,7 @@ IS_AM_SUBCLASS(335x, 0x335)
 /*
  * Macros to detect individual cpu types.
  * These are only rarely needed.
- * cpu_is_omap330():   True for OMAP330
- * cpu_is_omap730():   True for OMAP730
- * cpu_is_omap850():   True for OMAP850
+ * cpu_is_omap310():   True for OMAP310
  * cpu_is_omap1510():  True for OMAP1510
  * cpu_is_omap1610():  True for OMAP1610
  * cpu_is_omap1611():  True for OMAP1611
@@ -267,8 +265,6 @@ static inline int is_omap ##type (void)                     \
 }
 
 IS_OMAP_TYPE(310, 0x0310)
-IS_OMAP_TYPE(730, 0x0730)
-IS_OMAP_TYPE(850, 0x0850)
 IS_OMAP_TYPE(1510, 0x1510)
 IS_OMAP_TYPE(1610, 0x1610)
 IS_OMAP_TYPE(1611, 0x1611)
@@ -282,8 +278,6 @@ IS_OMAP_TYPE(2430, 0x2430)
 IS_OMAP_TYPE(3430, 0x3430)
 
 #define cpu_is_omap310()               0
-#define cpu_is_omap730()               0
-#define cpu_is_omap850()               0
 #define cpu_is_omap1510()              0
 #define cpu_is_omap1610()              0
 #define cpu_is_omap5912()              0
@@ -300,19 +294,9 @@ IS_OMAP_TYPE(3430, 0x3430)
 
 /*
  * Whether we have MULTI_OMAP1 or not, we still need to distinguish
- * between 730 vs 850, 330 vs. 1510 and 1611B/5912 vs. 1710.
+ * between 310 vs. 1510 and 1611B/5912 vs. 1710.
  */
 
-#if defined(CONFIG_ARCH_OMAP730)
-# undef  cpu_is_omap730
-# define cpu_is_omap730()              is_omap730()
-#endif
-
-#if defined(CONFIG_ARCH_OMAP850)
-# undef  cpu_is_omap850
-# define cpu_is_omap850()              is_omap850()
-#endif
-
 #if defined(CONFIG_ARCH_OMAP15XX)
 # undef  cpu_is_omap310
 # undef  cpu_is_omap1510
index aeba71796ad943b0f412104682cab2a40cabda92..32394895920080b7aa5344016bb90a0199482072 100644 (file)
@@ -99,7 +99,7 @@
 
 /*
  * OMAP730/850 has a slightly different config for the pin mux.
- * - config regs are the OMAP7XX_IO_CONF_x regs (see omap730.h) regs and
+ * - config regs are the OMAP7XX_IO_CONF_x regs (see omap7xx.h) regs and
  *   not the FUNC_MUX_CTRL_x regs from hardware.h
  * - for pull-up/down, only has one enable bit which is is in the same register
  *   as mux config
diff --git a/arch/arm/plat-omap/include/plat/omap730.h b/arch/arm/plat-omap/include/plat/omap730.h
deleted file mode 100644 (file)
index 14272bc..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* arch/arm/plat-omap/include/mach/omap730.h
- *
- * Hardware definitions for TI OMAP730 processor.
- *
- * Cleanup for Linux-2.6 by Dirk Behme <dirk.behme@de.bosch.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ASM_ARCH_OMAP730_H
-#define __ASM_ARCH_OMAP730_H
-
-/*
- * ----------------------------------------------------------------------------
- * Base addresses
- * ----------------------------------------------------------------------------
- */
-
-/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
-
-#define OMAP730_DSP_BASE       0xE0000000
-#define OMAP730_DSP_SIZE       0x50000
-#define OMAP730_DSP_START      0xE0000000
-
-#define OMAP730_DSPREG_BASE    0xE1000000
-#define OMAP730_DSPREG_SIZE    SZ_128K
-#define OMAP730_DSPREG_START   0xE1000000
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP730 specific configuration registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP730_CONFIG_BASE    0xfffe1000
-#define OMAP730_IO_CONF_0      0xfffe1070
-#define OMAP730_IO_CONF_1      0xfffe1074
-#define OMAP730_IO_CONF_2      0xfffe1078
-#define OMAP730_IO_CONF_3      0xfffe107c
-#define OMAP730_IO_CONF_4      0xfffe1080
-#define OMAP730_IO_CONF_5      0xfffe1084
-#define OMAP730_IO_CONF_6      0xfffe1088
-#define OMAP730_IO_CONF_7      0xfffe108c
-#define OMAP730_IO_CONF_8      0xfffe1090
-#define OMAP730_IO_CONF_9      0xfffe1094
-#define OMAP730_IO_CONF_10     0xfffe1098
-#define OMAP730_IO_CONF_11     0xfffe109c
-#define OMAP730_IO_CONF_12     0xfffe10a0
-#define OMAP730_IO_CONF_13     0xfffe10a4
-
-#define OMAP730_MODE_1         0xfffe1010
-#define OMAP730_MODE_2         0xfffe1014
-
-/* CSMI specials: in terms of base + offset */
-#define OMAP730_MODE2_OFFSET   0x14
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP730 traffic controller configuration registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP730_FLASH_CFG_0    0xfffecc10
-#define OMAP730_FLASH_ACFG_0   0xfffecc50
-#define OMAP730_FLASH_CFG_1    0xfffecc14
-#define OMAP730_FLASH_ACFG_1   0xfffecc54
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP730 DSP control registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP730_ICR_BASE       0xfffbb800
-#define OMAP730_DSP_M_CTL      0xfffbb804
-#define OMAP730_DSP_MMU_BASE   0xfffed200
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP730 PCC_UPLD configuration registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP730_PCC_UPLD_CTRL_BASE     (0xfffe0900)
-#define OMAP730_PCC_UPLD_CTRL          (OMAP730_PCC_UPLD_CTRL_BASE + 0x00)
-
-#endif /*  __ASM_ARCH_OMAP730_H */
-
diff --git a/arch/arm/plat-omap/include/plat/omap850.h b/arch/arm/plat-omap/include/plat/omap850.h
deleted file mode 100644 (file)
index c33f679..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* arch/arm/plat-omap/include/mach/omap850.h
- *
- * Hardware definitions for TI OMAP850 processor.
- *
- * Derived from omap730.h by Zebediah C. McClure <zmc@lurian.net>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ASM_ARCH_OMAP850_H
-#define __ASM_ARCH_OMAP850_H
-
-/*
- * ----------------------------------------------------------------------------
- * Base addresses
- * ----------------------------------------------------------------------------
- */
-
-/* Syntax: XX_BASE = Virtual base address, XX_START = Physical base address */
-
-#define OMAP850_DSP_BASE       0xE0000000
-#define OMAP850_DSP_SIZE       0x50000
-#define OMAP850_DSP_START      0xE0000000
-
-#define OMAP850_DSPREG_BASE    0xE1000000
-#define OMAP850_DSPREG_SIZE    SZ_128K
-#define OMAP850_DSPREG_START   0xE1000000
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP850 specific configuration registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP850_CONFIG_BASE    0xfffe1000
-#define OMAP850_IO_CONF_0      0xfffe1070
-#define OMAP850_IO_CONF_1      0xfffe1074
-#define OMAP850_IO_CONF_2      0xfffe1078
-#define OMAP850_IO_CONF_3      0xfffe107c
-#define OMAP850_IO_CONF_4      0xfffe1080
-#define OMAP850_IO_CONF_5      0xfffe1084
-#define OMAP850_IO_CONF_6      0xfffe1088
-#define OMAP850_IO_CONF_7      0xfffe108c
-#define OMAP850_IO_CONF_8      0xfffe1090
-#define OMAP850_IO_CONF_9      0xfffe1094
-#define OMAP850_IO_CONF_10     0xfffe1098
-#define OMAP850_IO_CONF_11     0xfffe109c
-#define OMAP850_IO_CONF_12     0xfffe10a0
-#define OMAP850_IO_CONF_13     0xfffe10a4
-
-#define OMAP850_MODE_1         0xfffe1010
-#define OMAP850_MODE_2         0xfffe1014
-
-/* CSMI specials: in terms of base + offset */
-#define OMAP850_MODE2_OFFSET   0x14
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP850 traffic controller configuration registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP850_FLASH_CFG_0    0xfffecc10
-#define OMAP850_FLASH_ACFG_0   0xfffecc50
-#define OMAP850_FLASH_CFG_1    0xfffecc14
-#define OMAP850_FLASH_ACFG_1   0xfffecc54
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP850 DSP control registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP850_ICR_BASE       0xfffbb800
-#define OMAP850_DSP_M_CTL      0xfffbb804
-#define OMAP850_DSP_MMU_BASE   0xfffed200
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP850 PCC_UPLD configuration registers
- * ----------------------------------------------------------------------------
- */
-#define OMAP850_PCC_UPLD_CTRL_BASE     (0xfffe0900)
-#define OMAP850_PCC_UPLD_CTRL          (OMAP850_PCC_UPLD_CTRL_BASE + 0x00)
-
-#endif /*  __ASM_ARCH_OMAP850_H */
-
index ad32621aa52e259fe20346d60f5d9f7d38edbad6..5e13c3884aa441c099bd274ef51d27acf36e06ab 100644 (file)
@@ -282,6 +282,8 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
                }
                mbox->rxq = mq;
                mq->mbox = mbox;
+
+               omap_mbox_enable_irq(mbox, IRQ_RX);
        }
        mutex_unlock(&mbox_configured_lock);
        return 0;
@@ -305,6 +307,7 @@ static void omap_mbox_fini(struct omap_mbox *mbox)
        mutex_lock(&mbox_configured_lock);
 
        if (!--mbox->use_count) {
+               omap_mbox_disable_irq(mbox, IRQ_RX);
                free_irq(mbox->irq, mbox);
                tasklet_kill(&mbox->txq->tasklet);
                flush_work_sync(&mbox->rxq->work);
@@ -338,13 +341,15 @@ struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
        if (!mbox)
                return ERR_PTR(-ENOENT);
 
-       ret = omap_mbox_startup(mbox);
-       if (ret)
-               return ERR_PTR(-ENODEV);
-
        if (nb)
                blocking_notifier_chain_register(&mbox->notifier, nb);
 
+       ret = omap_mbox_startup(mbox);
+       if (ret) {
+               blocking_notifier_chain_unregister(&mbox->notifier, nb);
+               return ERR_PTR(-ENODEV);
+       }
+
        return mbox;
 }
 EXPORT_SYMBOL(omap_mbox_get);
index a2fae4ea0936655b0f3b0131c1be748c943c71ee..7aca31c1df1fe57ac91b4278b13ad8036a8dac93 100644 (file)
@@ -78,6 +78,10 @@ config S5P_HRT
 
 # clock options
 
+config SAMSUNG_CLOCK
+       bool
+       default y if !COMMON_CLK
+
 config SAMSUNG_CLKSRC
        bool
        help
@@ -491,14 +495,6 @@ config S5P_SLEEP
          Internal config node to apply common S5P sleep management code.
          Can be selected by S5P and newer SoCs with similar sleep procedure.
 
-comment "Power Domain"
-
-config SAMSUNG_PD
-       bool "Samsung Power Domain"
-       depends on PM_RUNTIME
-       help
-         Say Y here if you want to control Power Domain by Runtime PM.
-
 config DEBUG_S3C_UART
        depends on PLAT_SAMSUNG
        int
index 860b2db4db155062b66361ce6688a11d6b86ff49..b78717496677fae8e17ba77392785aeea90e9ffd 100644 (file)
@@ -15,8 +15,8 @@ obj-y                         += init.o cpu.o
 obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET)   += time.o
 obj-$(CONFIG_S5P_HRT)          += s5p-time.o
 
-obj-y                          += clock.o
-obj-y                          += pwm-clock.o
+obj-$(CONFIG_SAMSUNG_CLOCK)    += clock.o
+obj-$(CONFIG_SAMSUNG_CLOCK)    += pwm-clock.o
 
 obj-$(CONFIG_SAMSUNG_CLKSRC)   += clock-clksrc.o
 obj-$(CONFIG_S5P_CLOCK)                += s5p-clock.o
@@ -60,10 +60,6 @@ obj-$(CONFIG_SAMSUNG_WAKEMASK)       += wakeup-mask.o
 obj-$(CONFIG_S5P_PM)           += s5p-pm.o s5p-irq-pm.o
 obj-$(CONFIG_S5P_SLEEP)                += s5p-sleep.o
 
-# PD support
-
-obj-$(CONFIG_SAMSUNG_PD)       += pd.o
-
 # PWM support
 
 obj-$(CONFIG_HAVE_PWM)         += pwm.o
index 33ecd0c9f0c3ecfdc63aaf44cab40a8deabd5f0c..b1e05ccff3acdb2ff4e5585ea1fb4947ebd18f28 100644 (file)
@@ -157,11 +157,13 @@ int s3c_adc_start(struct s3c_adc_client *client,
                return -EINVAL;
        }
 
-       if (client->is_ts && adc->ts_pend)
-               return -EAGAIN;
-
        spin_lock_irqsave(&adc->lock, flags);
 
+       if (client->is_ts && adc->ts_pend) {
+               spin_unlock_irqrestore(&adc->lock, flags);
+               return -EAGAIN;
+       }
+
        client->channel = channel;
        client->nr_samples = nr_samples;
 
index 1d214cb9d77050c921dc7e69f8b165c2eb89ee7e..74e31ce355388bd7c2062b35fb30e09ca085b3f5 100644 (file)
@@ -126,7 +126,8 @@ struct platform_device s3c_device_adc = {
 #ifdef CONFIG_CPU_S3C2440
 static struct resource s3c_camif_resource[] = {
        [0] = DEFINE_RES_MEM(S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF),
-       [1] = DEFINE_RES_IRQ(IRQ_CAM),
+       [1] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_C),
+       [2] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_P),
 };
 
 struct platform_device s3c_device_camif = {
@@ -1512,7 +1513,7 @@ static struct resource s3c64xx_spi0_resource[] = {
 };
 
 struct platform_device s3c64xx_device_spi0 = {
-       .name           = "s3c64xx-spi",
+       .name           = "s3c6410-spi",
        .id             = 0,
        .num_resources  = ARRAY_SIZE(s3c64xx_spi0_resource),
        .resource       = s3c64xx_spi0_resource,
@@ -1522,13 +1523,10 @@ struct platform_device s3c64xx_device_spi0 = {
        },
 };
 
-void __init s3c64xx_spi0_set_platdata(struct s3c64xx_spi_info *pd,
-                                     int src_clk_nr, int num_cs)
+void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
+                                               int num_cs)
 {
-       if (!pd) {
-               pr_err("%s:Need to pass platform data\n", __func__);
-               return;
-       }
+       struct s3c64xx_spi_info pd;
 
        /* Reject invalid configuration */
        if (!num_cs || src_clk_nr < 0) {
@@ -1536,12 +1534,11 @@ void __init s3c64xx_spi0_set_platdata(struct s3c64xx_spi_info *pd,
                return;
        }
 
-       pd->num_cs = num_cs;
-       pd->src_clk_nr = src_clk_nr;
-       if (!pd->cfg_gpio)
-               pd->cfg_gpio = s3c64xx_spi0_cfg_gpio;
+       pd.num_cs = num_cs;
+       pd.src_clk_nr = src_clk_nr;
+       pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
 
-       s3c_set_platdata(pd, sizeof(*pd), &s3c64xx_device_spi0);
+       s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0);
 }
 #endif /* CONFIG_S3C64XX_DEV_SPI0 */
 
@@ -1554,7 +1551,7 @@ static struct resource s3c64xx_spi1_resource[] = {
 };
 
 struct platform_device s3c64xx_device_spi1 = {
-       .name           = "s3c64xx-spi",
+       .name           = "s3c6410-spi",
        .id             = 1,
        .num_resources  = ARRAY_SIZE(s3c64xx_spi1_resource),
        .resource       = s3c64xx_spi1_resource,
@@ -1564,26 +1561,20 @@ struct platform_device s3c64xx_device_spi1 = {
        },
 };
 
-void __init s3c64xx_spi1_set_platdata(struct s3c64xx_spi_info *pd,
-                                     int src_clk_nr, int num_cs)
+void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
+                                               int num_cs)
 {
-       if (!pd) {
-               pr_err("%s:Need to pass platform data\n", __func__);
-               return;
-       }
-
        /* Reject invalid configuration */
        if (!num_cs || src_clk_nr < 0) {
                pr_err("%s: Invalid SPI configuration\n", __func__);
                return;
        }
 
-       pd->num_cs = num_cs;
-       pd->src_clk_nr = src_clk_nr;
-       if (!pd->cfg_gpio)
-               pd->cfg_gpio = s3c64xx_spi1_cfg_gpio;
+       pd.num_cs = num_cs;
+       pd.src_clk_nr = src_clk_nr;
+       pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
 
-       s3c_set_platdata(pd, sizeof(*pd), &s3c64xx_device_spi1);
+       s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
 }
 #endif /* CONFIG_S3C64XX_DEV_SPI1 */
 
@@ -1596,7 +1587,7 @@ static struct resource s3c64xx_spi2_resource[] = {
 };
 
 struct platform_device s3c64xx_device_spi2 = {
-       .name           = "s3c64xx-spi",
+       .name           = "s3c6410-spi",
        .id             = 2,
        .num_resources  = ARRAY_SIZE(s3c64xx_spi2_resource),
        .resource       = s3c64xx_spi2_resource,
@@ -1606,13 +1597,10 @@ struct platform_device s3c64xx_device_spi2 = {
        },
 };
 
-void __init s3c64xx_spi2_set_platdata(struct s3c64xx_spi_info *pd,
-                                     int src_clk_nr, int num_cs)
+void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
+                                               int num_cs)
 {
-       if (!pd) {
-               pr_err("%s:Need to pass platform data\n", __func__);
-               return;
-       }
+       struct s3c64xx_spi_info pd;
 
        /* Reject invalid configuration */
        if (!num_cs || src_clk_nr < 0) {
@@ -1620,11 +1608,10 @@ void __init s3c64xx_spi2_set_platdata(struct s3c64xx_spi_info *pd,
                return;
        }
 
-       pd->num_cs = num_cs;
-       pd->src_clk_nr = src_clk_nr;
-       if (!pd->cfg_gpio)
-               pd->cfg_gpio = s3c64xx_spi2_cfg_gpio;
+       pd.num_cs = num_cs;
+       pd.src_clk_nr = src_clk_nr;
+       pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
 
-       s3c_set_platdata(pd, sizeof(*pd), &s3c64xx_device_spi2);
+       s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);
 }
 #endif /* CONFIG_S3C64XX_DEV_SPI2 */
index eb9f4f5340060d432f7fd6741a3acfc6fbfa2dbc..c38d75489240fc34476ef9bfd2a3caa010df2967 100644 (file)
 #include <mach/dma.h>
 
 static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
-                               struct samsung_dma_info *info)
+                               struct samsung_dma_req *param)
 {
-       struct dma_chan *chan;
        dma_cap_mask_t mask;
-       struct dma_slave_config slave_config;
        void *filter_param;
 
        dma_cap_zero(mask);
-       dma_cap_set(info->cap, mask);
+       dma_cap_set(param->cap, mask);
 
        /*
         * If a dma channel property of a device node from device tree is
         * specified, use that as the fliter parameter.
         */
-       filter_param = (dma_ch == DMACH_DT_PROP) ? (void *)info->dt_dmach_prop :
-                               (void *)dma_ch;
-       chan = dma_request_channel(mask, pl330_filter, filter_param);
+       filter_param = (dma_ch == DMACH_DT_PROP) ?
+               (void *)param->dt_dmach_prop : (void *)dma_ch;
+       return (unsigned)dma_request_channel(mask, pl330_filter, filter_param);
+}
+
+static int samsung_dmadev_release(unsigned ch, void *param)
+{
+       dma_release_channel((struct dma_chan *)ch);
 
-       if (info->direction == DMA_DEV_TO_MEM) {
+       return 0;
+}
+
+static int samsung_dmadev_config(unsigned ch,
+                               struct samsung_dma_config *param)
+{
+       struct dma_chan *chan = (struct dma_chan *)ch;
+       struct dma_slave_config slave_config;
+
+       if (param->direction == DMA_DEV_TO_MEM) {
                memset(&slave_config, 0, sizeof(struct dma_slave_config));
-               slave_config.direction = info->direction;
-               slave_config.src_addr = info->fifo;
-               slave_config.src_addr_width = info->width;
+               slave_config.direction = param->direction;
+               slave_config.src_addr = param->fifo;
+               slave_config.src_addr_width = param->width;
                slave_config.src_maxburst = 1;
                dmaengine_slave_config(chan, &slave_config);
-       } else if (info->direction == DMA_MEM_TO_DEV) {
+       } else if (param->direction == DMA_MEM_TO_DEV) {
                memset(&slave_config, 0, sizeof(struct dma_slave_config));
-               slave_config.direction = info->direction;
-               slave_config.dst_addr = info->fifo;
-               slave_config.dst_addr_width = info->width;
+               slave_config.direction = param->direction;
+               slave_config.dst_addr = param->fifo;
+               slave_config.dst_addr_width = param->width;
                slave_config.dst_maxburst = 1;
                dmaengine_slave_config(chan, &slave_config);
+       } else {
+               pr_warn("unsupported direction\n");
+               return -EINVAL;
        }
 
-       return (unsigned)chan;
-}
-
-static int samsung_dmadev_release(unsigned ch,
-                       struct s3c2410_dma_client *client)
-{
-       dma_release_channel((struct dma_chan *)ch);
-
        return 0;
 }
 
 static int samsung_dmadev_prepare(unsigned ch,
-                       struct samsung_dma_prep_info *info)
+                       struct samsung_dma_prep *param)
 {
        struct scatterlist sg;
        struct dma_chan *chan = (struct dma_chan *)ch;
        struct dma_async_tx_descriptor *desc;
 
-       switch (info->cap) {
+       switch (param->cap) {
        case DMA_SLAVE:
                sg_init_table(&sg, 1);
-               sg_dma_len(&sg) = info->len;
-               sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
-                           info->len, offset_in_page(info->buf));
-               sg_dma_address(&sg) = info->buf;
+               sg_dma_len(&sg) = param->len;
+               sg_set_page(&sg, pfn_to_page(PFN_DOWN(param->buf)),
+                           param->len, offset_in_page(param->buf));
+               sg_dma_address(&sg) = param->buf;
 
                desc = dmaengine_prep_slave_sg(chan,
-                       &sg, 1, info->direction, DMA_PREP_INTERRUPT);
+                       &sg, 1, param->direction, DMA_PREP_INTERRUPT);
                break;
        case DMA_CYCLIC:
-               desc = dmaengine_prep_dma_cyclic(chan,
-                       info->buf, info->len, info->period, info->direction);
+               desc = dmaengine_prep_dma_cyclic(chan, param->buf,
+                       param->len, param->period, param->direction);
                break;
        default:
                dev_err(&chan->dev->device, "unsupported format\n");
@@ -96,8 +103,8 @@ static int samsung_dmadev_prepare(unsigned ch,
                return -EFAULT;
        }
 
-       desc->callback = info->fp;
-       desc->callback_param = info->fp_param;
+       desc->callback = param->fp;
+       desc->callback_param = param->fp_param;
 
        dmaengine_submit((struct dma_async_tx_descriptor *)desc);
 
@@ -119,6 +126,7 @@ static inline int samsung_dmadev_flush(unsigned ch)
 static struct samsung_dma_ops dmadev_ops = {
        .request        = samsung_dmadev_request,
        .release        = samsung_dmadev_release,
+       .config         = samsung_dmadev_config,
        .prepare        = samsung_dmadev_prepare,
        .trigger        = samsung_dmadev_trigger,
        .started        = NULL,
index 0721293fad635b913a3a07f082f13aba32ea0179..ace4451b7651388053eeaa8644e0a3f8856c54e8 100644 (file)
@@ -132,6 +132,10 @@ IS_SAMSUNG_CPU(exynos5250, EXYNOS5250_SOC_ID, EXYNOS5_SOC_MASK)
 
 #define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
 
+#ifndef KHZ
+#define KHZ (1000)
+#endif
+
 #ifndef MHZ
 #define MHZ (1000*1000)
 #endif
index 61ca2f356c52d6d4ea3fac036788cc422aa02235..5da4b4f38f40ebb41c076fbe74bd205aefefdacf 100644 (file)
@@ -131,7 +131,6 @@ extern struct platform_device exynos4_device_ohci;
 extern struct platform_device exynos4_device_pcm0;
 extern struct platform_device exynos4_device_pcm1;
 extern struct platform_device exynos4_device_pcm2;
-extern struct platform_device exynos4_device_pd[];
 extern struct platform_device exynos4_device_spdif;
 
 extern struct platform_device exynos_device_drm;
index 71a6827c7706b21e10200bd834b5dbaad1fa9e45..f5144cdd300106b5afb936015a35251eae1d2de9 100644 (file)
 #include <linux/dmaengine.h>
 #include <mach/dma.h>
 
-struct samsung_dma_prep_info {
+struct samsung_dma_req {
+       enum dma_transaction_type cap;
+       struct property *dt_dmach_prop;
+       struct s3c2410_dma_client *client;
+};
+
+struct samsung_dma_prep {
        enum dma_transaction_type cap;
        enum dma_transfer_direction direction;
        dma_addr_t buf;
@@ -26,19 +32,17 @@ struct samsung_dma_prep_info {
        void *fp_param;
 };
 
-struct samsung_dma_info {
-       enum dma_transaction_type cap;
+struct samsung_dma_config {
        enum dma_transfer_direction direction;
        enum dma_slave_buswidth width;
        dma_addr_t fifo;
-       struct s3c2410_dma_client *client;
-       struct property *dt_dmach_prop;
 };
 
 struct samsung_dma_ops {
-       unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
-       int (*release)(unsigned ch, struct s3c2410_dma_client *client);
-       int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
+       unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param);
+       int (*release)(unsigned ch, void *param);
+       int (*config)(unsigned ch, struct samsung_dma_config *param);
+       int (*prepare)(unsigned ch, struct samsung_dma_prep *param);
        int (*trigger)(unsigned ch);
        int (*started)(unsigned ch);
        int (*flush)(unsigned ch);
index 536002ff2ab8d665993b1f554a90ac74642917ad..b885322717a14258a74675062d792705b0bd849e 100644 (file)
@@ -43,7 +43,6 @@ struct s3c_fb_pd_win {
  * @setup_gpio: Setup the external GPIO pins to the right state to transfer
  *             the data from the display system to the connected display
  *             device.
- * @default_win: default window layer number to be used for UI layer.
  * @vidcon0: The base vidcon0 values to control the panel data format.
  * @vidcon1: The base vidcon1 values to control the panel data output.
  * @vtiming: Video timing when connected to a RGB type panel.
diff --git a/arch/arm/plat-samsung/include/plat/pd.h b/arch/arm/plat-samsung/include/plat/pd.h
deleted file mode 100644 (file)
index abb4bc3..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* linux/arch/arm/plat-samsung/include/plat/pd.h
- *
- * Copyright (c) 2010-2011 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 version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_PLAT_SAMSUNG_PD_H
-#define __ASM_PLAT_SAMSUNG_PD_H __FILE__
-
-struct samsung_pd_info {
-       int (*enable)(struct device *dev);
-       int (*disable)(struct device *dev);
-       void __iomem *base;
-};
-
-enum exynos4_pd_block {
-       PD_MFC,
-       PD_G3D,
-       PD_LCD0,
-       PD_LCD1,
-       PD_TV,
-       PD_CAM,
-       PD_GPS
-};
-
-#endif /* __ASM_PLAT_SAMSUNG_PD_H */
index fa95e9a009729f41ddd1c39174e4f6908f515226..ceba18d23a5a530ef233f5f5ecfe0e987cb87274 100644 (file)
@@ -18,7 +18,6 @@ struct platform_device;
  * @fb_delay: Slave specific feedback delay.
  *            Refer to FB_CLK_SEL register definition in SPI chapter.
  * @line: Custom 'identity' of the CS line.
- * @set_level: CS line control.
  *
  * This is per SPI-Slave Chipselect information.
  * Allocate and initialize one in machine init code and make the
@@ -27,57 +26,41 @@ struct platform_device;
 struct s3c64xx_spi_csinfo {
        u8 fb_delay;
        unsigned line;
-       void (*set_level)(unsigned line_id, int lvl);
 };
 
 /**
  * struct s3c64xx_spi_info - SPI Controller defining structure
  * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
- * @clk_from_cmu: If the SPI clock/prescalar control block is present
- *     by the platform's clock-management-unit and not in SPI controller.
  * @num_cs: Number of CS this controller emulates.
  * @cfg_gpio: Configure pins for this SPI controller.
- * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
- * @rx_lvl_offset: Depends on tx fifo_lvl field and bus number
- * @high_speed: If the controller supports HIGH_SPEED_EN bit
- * @tx_st_done: Depends on tx fifo_lvl field
  */
 struct s3c64xx_spi_info {
        int src_clk_nr;
-       bool clk_from_cmu;
-
        int num_cs;
-
-       int (*cfg_gpio)(struct platform_device *pdev);
-
-       /* Following two fields are for future compatibility */
-       int fifo_lvl_mask;
-       int rx_lvl_offset;
-       int high_speed;
-       int tx_st_done;
+       int (*cfg_gpio)(void);
 };
 
 /**
  * s3c64xx_spi_set_platdata - SPI Controller configure callback by the board
  *                             initialization code.
- * @pd: SPI platform data to set.
+ * @cfg_gpio: Pointer to gpio setup function.
  * @src_clk_nr: Clock the SPI controller is to use to generate SPI clocks.
  * @num_cs: Number of elements in the 'cs' array.
  *
  * Call this from machine init code for each SPI Controller that
  * has some chips attached to it.
  */
-extern void s3c64xx_spi0_set_platdata(struct s3c64xx_spi_info *pd,
-                                     int src_clk_nr, int num_cs);
-extern void s3c64xx_spi1_set_platdata(struct s3c64xx_spi_info *pd,
-                                     int src_clk_nr, int num_cs);
-extern void s3c64xx_spi2_set_platdata(struct s3c64xx_spi_info *pd,
-                                     int src_clk_nr, int num_cs);
+extern void s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
+                                               int num_cs);
+extern void s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
+                                               int num_cs);
+extern void s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
+                                               int num_cs);
 
 /* defined by architecture to configure gpio */
-extern int s3c64xx_spi0_cfg_gpio(struct platform_device *dev);
-extern int s3c64xx_spi1_cfg_gpio(struct platform_device *dev);
-extern int s3c64xx_spi2_cfg_gpio(struct platform_device *dev);
+extern int s3c64xx_spi0_cfg_gpio(void);
+extern int s3c64xx_spi1_cfg_gpio(void);
+extern int s3c64xx_spi2_cfg_gpio(void);
 
 extern struct s3c64xx_spi_info s3c64xx_spi0_pdata;
 extern struct s3c64xx_spi_info s3c64xx_spi1_pdata;
diff --git a/arch/arm/plat-samsung/pd.c b/arch/arm/plat-samsung/pd.c
deleted file mode 100644 (file)
index 312b510..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/* linux/arch/arm/plat-samsung/pd.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Samsung Power domain support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/init.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/pm_runtime.h>
-
-#include <plat/pd.h>
-
-static int samsung_pd_probe(struct platform_device *pdev)
-{
-       struct samsung_pd_info *pdata = pdev->dev.platform_data;
-       struct device *dev = &pdev->dev;
-
-       if (!pdata) {
-               dev_err(dev, "no device data specified\n");
-               return -ENOENT;
-       }
-
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
-
-       dev_info(dev, "power domain registered\n");
-       return 0;
-}
-
-static int __devexit samsung_pd_remove(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-
-       pm_runtime_disable(dev);
-       return 0;
-}
-
-static int samsung_pd_runtime_suspend(struct device *dev)
-{
-       struct samsung_pd_info *pdata = dev->platform_data;
-       int ret = 0;
-
-       if (pdata->disable)
-               ret = pdata->disable(dev);
-
-       dev_dbg(dev, "suspended\n");
-       return ret;
-}
-
-static int samsung_pd_runtime_resume(struct device *dev)
-{
-       struct samsung_pd_info *pdata = dev->platform_data;
-       int ret = 0;
-
-       if (pdata->enable)
-               ret = pdata->enable(dev);
-
-       dev_dbg(dev, "resumed\n");
-       return ret;
-}
-
-static const struct dev_pm_ops samsung_pd_pm_ops = {
-       .runtime_suspend        = samsung_pd_runtime_suspend,
-       .runtime_resume         = samsung_pd_runtime_resume,
-};
-
-static struct platform_driver samsung_pd_driver = {
-       .driver         = {
-               .name           = "samsung-pd",
-               .owner          = THIS_MODULE,
-               .pm             = &samsung_pd_pm_ops,
-       },
-       .probe          = samsung_pd_probe,
-       .remove         = __devexit_p(samsung_pd_remove),
-};
-
-static int __init samsung_pd_init(void)
-{
-       int ret;
-
-       ret = platform_driver_register(&samsung_pd_driver);
-       if (ret)
-               printk(KERN_ERR "%s: failed to add PD driver\n", __func__);
-
-       return ret;
-}
-arch_initcall(samsung_pd_init);
index c559d8438c70ee2d873afc43a7d14ee1fc2002c2..d3583050fb05461d83af523a9d1f909d9994c094 100644 (file)
@@ -36,7 +36,6 @@ struct pwm_device {
        unsigned int             duty_ns;
 
        unsigned char            tcon_base;
-       unsigned char            running;
        unsigned char            use_count;
        unsigned char            pwm_id;
 };
@@ -116,7 +115,6 @@ int pwm_enable(struct pwm_device *pwm)
 
        local_irq_restore(flags);
 
-       pwm->running = 1;
        return 0;
 }
 
@@ -134,8 +132,6 @@ void pwm_disable(struct pwm_device *pwm)
        __raw_writel(tcon, S3C2410_TCON);
 
        local_irq_restore(flags);
-
-       pwm->running = 0;
 }
 
 EXPORT_SYMBOL(pwm_disable);
index 78149491282749adf6c71051c1321c35c9404077..f99448c48d30dc93d1dcd7a3f9658b523a9e10dd 100644 (file)
@@ -36,30 +36,26 @@ static void s3c_dma_cb(struct s3c2410_dma_chan *channel, void *param,
 }
 
 static unsigned s3c_dma_request(enum dma_ch dma_ch,
-                                struct samsung_dma_info *info)
+                                       struct samsung_dma_req *param)
 {
        struct cb_data *data;
 
-       if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
-               s3c2410_dma_free(dma_ch, info->client);
+       if (s3c2410_dma_request(dma_ch, param->client, NULL) < 0) {
+               s3c2410_dma_free(dma_ch, param->client);
                return 0;
        }
 
+       if (param->cap == DMA_CYCLIC)
+               s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
+
        data = kzalloc(sizeof(struct cb_data), GFP_KERNEL);
        data->ch = dma_ch;
        list_add_tail(&data->node, &dma_list);
 
-       s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo);
-
-       if (info->cap == DMA_CYCLIC)
-               s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
-
-       s3c2410_dma_config(dma_ch, info->width);
-
        return (unsigned)dma_ch;
 }
 
-static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client)
+static int s3c_dma_release(unsigned ch, void *param)
 {
        struct cb_data *data;
 
@@ -68,16 +64,24 @@ static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client)
                        break;
        list_del(&data->node);
 
-       s3c2410_dma_free(ch, client);
+       s3c2410_dma_free(ch, param);
        kfree(data);
 
        return 0;
 }
 
-static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
+static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
+{
+       s3c2410_dma_devconfig(ch, param->direction, param->fifo);
+       s3c2410_dma_config(ch, param->width);
+
+       return 0;
+}
+
+static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
 {
        struct cb_data *data;
-       int len = (info->cap == DMA_CYCLIC) ? info->period : info->len;
+       int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
 
        list_for_each_entry(data, &dma_list, node)
                if (data->ch == ch)
@@ -85,11 +89,11 @@ static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
 
        if (!data->fp) {
                s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb);
-               data->fp = info->fp;
-               data->fp_param = info->fp_param;
+               data->fp = param->fp;
+               data->fp_param = param->fp_param;
        }
 
-       s3c2410_dma_enqueue(ch, (void *)data, info->buf, len);
+       s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
 
        return 0;
 }
@@ -117,6 +121,7 @@ static inline int s3c_dma_stop(unsigned ch)
 static struct samsung_dma_ops s3c_dma_ops = {
        .request        = s3c_dma_request,
        .release        = s3c_dma_release,
+       .config         = s3c_dma_config,
        .prepare        = s3c_dma_prepare,
        .trigger        = s3c_dma_trigger,
        .started        = s3c_dma_started,
index 031a61899beffb07843c198a3237c385e5e2100a..48a1599110372ffb77fcf8e33e89449e4a40b39d 100644 (file)
@@ -37,6 +37,7 @@ struct clk clk_ext_xtal_mux = {
 struct clk clk_xusbxti = {
        .name           = "xusbxti",
        .id             = -1,
+       .rate           = 24000000,
 };
 
 struct clk s5p_clk_27m = {
index 81ee7cc344575956a698ad929fe70ca8df1cee33..8d5c10a5084da5dcaa87855abacb9f0a7e005a02 100644 (file)
@@ -1,5 +1,8 @@
 if PLAT_VERSATILE
 
+config PLAT_VERSATILE_CLOCK
+       bool
+
 config PLAT_VERSATILE_CLCD
        bool
 
index a5cb1945bdcc7ec637f288bd65096e5a77ae12f7..272769a8a7d6532bbc0391c0228501467c9a3d95 100644 (file)
@@ -1,4 +1,4 @@
-obj-y  := clock.o
+obj-$(CONFIG_PLAT_VERSATILE_CLOCK) += clock.o
 obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
 obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o
 obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
index a09230a08e02d201e4c2b214a0bd6cabc5a8c223..62ef17676b406274a76ddf5d3a51f7091a9ace97 100644 (file)
@@ -70,4 +70,7 @@ extern int is_in_rom(unsigned long);
 #define        VMALLOC_END     0xffffffff
 
 #define arch_enter_lazy_cpu_mode()    do {} while (0)
+
+#include <asm-generic/pgtable.h>
+
 #endif /* _H8300_PGTABLE_H */
index 356068cd0879bdf145bd68f12857b75cfd95ab4c..8725d1ad427263895a6e5d904c179e2c1440bbe0 100644 (file)
@@ -100,7 +100,6 @@ extern int __put_user_bad(void);
        break;                                                  \
     default:                                                   \
        __gu_err = __get_user_bad();                            \
-       __gu_val = 0;                                           \
        break;                                                  \
     }                                                          \
     (x) = __gu_val;                                            \
@@ -159,4 +158,6 @@ clear_user(void *to, unsigned long n)
        return 0;
 }
 
+#define __clear_user   clear_user
+
 #endif /* _H8300_UACCESS_H */
index fca10378701bb9c818b8c123fb4d3c05522cd0c6..5adaadaf92183c42703b9995e32e622dc926d958 100644 (file)
@@ -447,7 +447,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
  */
-statis void do_signal(struct pt_regs *regs)
+static void do_signal(struct pt_regs *regs)
 {
        siginfo_t info;
        int signr;
index 32263a138aa6ccf9a2a871a859254f2a18df03d9..e0f74191d55312fe4a8fa6548d95d34667604efe 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/profile.h>
 
 #include <asm/io.h>
+#include <asm/irq_regs.h>
 #include <asm/timer.h>
 
 #define        TICK_SIZE (tick_nsec / 1000)
index f7264621e58ddf888708dcbe114320bd2d2fd934..149fbefc1a4d36988d6f5ce3422aaac57d029b60 100644 (file)
@@ -180,9 +180,7 @@ void __cpuinit start_secondary(void)
 
        notify_cpu_starting(cpu);
 
-       ipi_call_lock();
        set_cpu_online(cpu, true);
-       ipi_call_unlock();
 
        local_irq_enable();
 
index 1113b8aba07f5a0caa632ff01dc8111899e49185..963d2db53bfa55a9d50932b3301300d3411c3115 100644 (file)
@@ -382,7 +382,6 @@ smp_callin (void)
        set_numa_node(cpu_to_node_map[cpuid]);
        set_numa_mem(local_memory_node(cpu_to_node_map[cpuid]));
 
-       ipi_call_lock_irq();
        spin_lock(&vector_lock);
        /* Setup the per cpu irq handling data structures */
        __setup_vector_irq(cpuid);
@@ -390,7 +389,6 @@ smp_callin (void)
        set_cpu_online(cpuid, true);
        per_cpu(cpu_state, cpuid) = CPU_ONLINE;
        spin_unlock(&vector_lock);
-       ipi_call_unlock_irq();
 
        smp_setup_percpu_timer();
 
index 177716b1d61354a74a86ecfff0e08ba522660ec8..01729c2979ba2634f49f7c4403aab4e95652fead 100644 (file)
@@ -43,9 +43,9 @@ endif
 
 OBJCOPYFLAGS += -R .empty_zero_page
 
-suffix_$(CONFIG_KERNEL_GZIP)   = gz
-suffix_$(CONFIG_KERNEL_BZIP2)  = bz2
-suffix_$(CONFIG_KERNEL_LZMA)   = lzma
+suffix-$(CONFIG_KERNEL_GZIP)   = gz
+suffix-$(CONFIG_KERNEL_BZIP2)  = bz2
+suffix-$(CONFIG_KERNEL_LZMA)   = lzma
 
 $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE
        $(call if_changed,ld)
index 370d60881977db4370f1686bee5d3b59a19eba69..28a09529f206915fd00633bf846dde48342b8b36 100644 (file)
@@ -28,7 +28,7 @@ static unsigned long free_mem_ptr;
 static unsigned long free_mem_end_ptr;
 
 #ifdef CONFIG_KERNEL_BZIP2
-static void *memset(void *s, int c, size_t n)
+void *memset(void *s, int c, size_t n)
 {
        char *ss = s;
 
@@ -39,6 +39,16 @@ static void *memset(void *s, int c, size_t n)
 #endif
 
 #ifdef CONFIG_KERNEL_GZIP
+void *memcpy(void *dest, const void *src, size_t n)
+{
+       char *d = dest;
+       const char *s = src;
+       while (n--)
+               *d++ = *s++;
+
+       return dest;
+}
+
 #define BOOT_HEAP_SIZE             0x10000
 #include "../../../../lib/decompress_inflate.c"
 #endif
index 527527584dd096dc2d7c2cc55bab64e83df0fee6..4313aa62b51b76746b4b800a592b3f55899c395e 100644 (file)
@@ -113,9 +113,6 @@ struct pt_regs {
 
 #define PTRACE_OLDSETOPTIONS   21
 
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD  0x00000001
-
 #ifdef __KERNEL__
 
 #include <asm/m32r.h>          /* M32R_PSW_BSM, M32R_PSW_BPM */
index cf7829a615513e1597d903c6398348d8e0d5ac1e..c689b828dfe2b0b218d6ec523c0233fddd086785 100644 (file)
@@ -79,11 +79,6 @@ static __inline__ int cpu_number_map(int cpu)
        return cpu;
 }
 
-static __inline__ unsigned int num_booting_cpus(void)
-{
-       return cpumask_weight(&cpu_callout_map);
-}
-
 extern void smp_send_timer(void);
 extern unsigned long send_IPI_mask_phys(const cpumask_t*, int, int);
 
index 4c03361537aa6b49f3e2ba144afd667cd6b75307..51f5e9aa49016fdce8112eb72083c0b167f21df8 100644 (file)
@@ -591,17 +591,16 @@ void user_enable_single_step(struct task_struct *child)
 
        if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0)
            != sizeof(insn))
-               return -EIO;
+               return;
 
        compute_next_pc(insn, pc, &next_pc, child);
        if (next_pc & 0x80000000)
-               return -EIO;
+               return;
 
        if (embed_debug_trap(child, next_pc))
-               return -EIO;
+               return;
 
        invalidate_cache();
-       return 0;
 }
 
 void user_disable_single_step(struct task_struct *child)
index f3fb2c029cfcab061fbbfb5697273067e57c38e8..d0f60b97bbc5d82b1855e73145ce0b809124200f 100644 (file)
@@ -286,7 +286,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                        case -ERESTARTNOINTR:
                                regs->r0 = regs->orig_r0;
                                if (prev_insn(regs) < 0)
-                                       return -EFAULT;
+                                       return;
                }
        }
 
index 09ab87ee6fef654eef0220ab05b1224492947efc..b3e10fdd389866659212f947971af764b98dcf3f 100644 (file)
@@ -288,6 +288,7 @@ config MIPS_MALTA
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_HAS_CPU_MIPS32_R2
        select SYS_HAS_CPU_MIPS64_R1
+       select SYS_HAS_CPU_MIPS64_R2
        select SYS_HAS_CPU_NEVADA
        select SYS_HAS_CPU_RM7000
        select SYS_HAS_EARLY_PRINTK
@@ -1423,6 +1424,7 @@ config CPU_SB1
 config CPU_CAVIUM_OCTEON
        bool "Cavium Octeon processor"
        depends on SYS_HAS_CPU_CAVIUM_OCTEON
+       select ARCH_SPARSEMEM_ENABLE
        select CPU_HAS_PREFETCH
        select CPU_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_SMP
index 6210b8d841098c5182a7ea986e6ac66c6a02371b..b311be45a7207028a7cf6df754a8b54c0f259938 100644 (file)
@@ -21,6 +21,7 @@ config BCM47XX_BCMA
        select BCMA
        select BCMA_HOST_SOC
        select BCMA_DRIVER_MIPS
+       select BCMA_HOST_PCI if PCI
        select BCMA_DRIVER_PCI_HOSTMODE if PCI
        default y
        help
index de4d917fd54d5ae99fa3ec69e55666a4fe3945cc..a551bab5ecb94b2aafce31787cea8e6bb31dbd10 100644 (file)
@@ -79,11 +79,11 @@ static int __init config_pcmcia_cs(unsigned int cs,
        return ret;
 }
 
-static const __initdata struct {
+static const struct {
        unsigned int    cs;
        unsigned int    base;
        unsigned int    size;
-} pcmcia_cs[3] = {
+} pcmcia_cs[3] __initconst = {
        {
                .cs     = MPI_CS_PCMCIA_COMMON,
                .base   = BCM_PCMCIA_COMMON_BASE_PA,
index f9e275a50d982be23ffda94a1e23d019c25569b5..2f4f6d5e05b66bdad381da0ddaff5b83d3897d51 100644 (file)
@@ -82,10 +82,6 @@ config CAVIUM_OCTEON_LOCK_L2_MEMCPY
        help
          Lock the kernel's implementation of memcpy() into L2.
 
-config ARCH_SPARSEMEM_ENABLE
-       def_bool y
-       select SPARSEMEM_STATIC
-
 config IOMMU_HELPER
        bool
 
index 4b93048044eb266457b4c9ac80a164c056e6eba9..ee1fb9f7f517c29e1ce6781699cbf90e75a314ce 100644 (file)
@@ -185,7 +185,6 @@ static void __cpuinit octeon_init_secondary(void)
        octeon_init_cvmcount();
 
        octeon_irq_setup_secondary();
-       raw_local_irq_enable();
 }
 
 /**
@@ -233,6 +232,7 @@ static void octeon_smp_finish(void)
 
        /* to generate the first CPU timer interrupt */
        write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
+       local_irq_enable();
 }
 
 /**
index 2e1ad4c652b72cf9042524870a19631f9e0566e0..82ad35ce2b45d975705e90a90db8cf82b7189255 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/irqflags.h>
 #include <linux/types.h>
 #include <asm/barrier.h>
-#include <asm/bug.h>
 #include <asm/byteorder.h>             /* sigh ... */
 #include <asm/cpu-features.h>
 #include <asm/sgidefs.h>
index 285a41fa0b18dd0412a291805781f8d811ee82de..eee10dc07ac100defc6b0f00f6d8616da692e2c0 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __ASM_CMPXCHG_H
 #define __ASM_CMPXCHG_H
 
+#include <linux/bug.h>
 #include <linux/irqflags.h>
 #include <asm/war.h>
 
index f9fa2a479dd0e175ae7fc839d833b15695103f04..95e40c1e8ed114a3a95ad9cab9794e129ccbdca2 100644 (file)
@@ -94,6 +94,7 @@
 #define PRID_IMP_24KE          0x9600
 #define PRID_IMP_74K           0x9700
 #define PRID_IMP_1004K         0x9900
+#define PRID_IMP_M14KC         0x9c00
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
@@ -260,12 +261,12 @@ enum cpu_type_enum {
         */
        CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
        CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
-       CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC,
+       CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_M14KC,
 
        /*
         * MIPS64 class processors
         */
-       CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
+       CPU_5KC, CPU_5KE, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
        CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
        CPU_XLR, CPU_XLP,
 
@@ -288,7 +289,7 @@ enum cpu_type_enum {
 #define MIPS_CPU_ISA_M64R2     0x00000100
 
 #define MIPS_CPU_ISA_32BIT (MIPS_CPU_ISA_I | MIPS_CPU_ISA_II | \
-       MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 )
+       MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2)
 #define MIPS_CPU_ISA_64BIT (MIPS_CPU_ISA_III | MIPS_CPU_ISA_IV | \
        MIPS_CPU_ISA_V | MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)
 
index 86548da650e765f79db345f4d3964a5d0eb6c0fe..991b659e254803937cc99c9854d2c24f1153b0d3 100644 (file)
 
 #define GIC_VPE_EIC_SHADOW_SET_BASE    0x0100
 #define GIC_VPE_EIC_SS(intr) \
-       (GIC_EIC_SHADOW_SET_BASE + (4 * intr))
+       (GIC_VPE_EIC_SHADOW_SET_BASE + (4 * intr))
 
 #define GIC_VPE_EIC_VEC_BASE           0x0800
 #define GIC_VPE_EIC_VEC(intr) \
@@ -330,6 +330,17 @@ struct gic_intr_map {
 #define GIC_FLAG_TRANSPARENT   0x02
 };
 
+/*
+ * This is only used in EIC mode. This helps to figure out which
+ * shared interrupts we need to process when we get a vector interrupt.
+ */
+#define GIC_MAX_SHARED_INTR  0x5
+struct gic_shared_intr_map {
+       unsigned int num_shared_intr;
+       unsigned int intr_list[GIC_MAX_SHARED_INTR];
+       unsigned int local_intr_mask;
+};
+
 extern void gic_init(unsigned long gic_base_addr,
        unsigned long gic_addrspace_size, struct gic_intr_map *intrmap,
        unsigned int intrmap_size, unsigned int irqbase);
@@ -338,5 +349,7 @@ extern unsigned int gic_get_int(void);
 extern void gic_send_ipi(unsigned int intr);
 extern unsigned int plat_ipi_call_int_xlate(unsigned int);
 extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
+extern void gic_bind_eic_interrupt(int irq, int set);
+extern unsigned int gic_get_timer_pending(void);
 
 #endif /* _ASM_GICREGS_H */
index 7ebfc392e58d1d5cb7c8f2a686e25a9041f853b8..ab84064283db2c50d847d888b32e42a4d316dd7d 100644 (file)
@@ -251,7 +251,7 @@ struct f_format {   /* FPU register format */
        unsigned int func : 6;
 };
 
-struct ma_format {     /* FPU multipy and add format (MIPS IV) */
+struct ma_format {     /* FPU multiply and add format (MIPS IV) */
        unsigned int opcode : 6;
        unsigned int fr : 5;
        unsigned int ft : 5;
@@ -324,7 +324,7 @@ struct f_format {   /* FPU register format */
        unsigned int opcode : 6;
 };
 
-struct ma_format {     /* FPU multipy and add format (MIPS IV) */
+struct ma_format {     /* FPU multiply and add format (MIPS IV) */
        unsigned int fmt : 2;
        unsigned int func : 4;
        unsigned int fd : 5;
index a58f22998a86507729e3d72d379ef6e23ddad019..29d9c23c20c72d87f847f28772666448cdd2711a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/types.h>
 
 #include <asm/addrspace.h>
+#include <asm/bug.h>
 #include <asm/byteorder.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
index fb698dc09bc9c39c60cf7c0d43992b424e239551..78dbb8a86da249d4bd4e6fa2db6b6c6b0c4bd4ed 100644 (file)
@@ -136,6 +136,7 @@ extern void free_irqno(unsigned int irq);
  * IE7.  Since R2 their number has to be read from the c0_intctl register.
  */
 #define CP0_LEGACY_COMPARE_IRQ 7
+#define CP0_LEGACY_PERFCNT_IRQ 7
 
 extern int cp0_compare_irq;
 extern int cp0_compare_irq_shift;
index 94d4faad29a1a4286c934d28e76175ca97eee935..fdcd78ca1b03d054f807ee0c64839c763194f855 100644 (file)
@@ -99,7 +99,7 @@
 #define CKCTL_6368_USBH_CLK_EN         (1 << 15)
 #define CKCTL_6368_DISABLE_GLESS_EN    (1 << 16)
 #define CKCTL_6368_NAND_CLK_EN         (1 << 17)
-#define CKCTL_6368_IPSEC_CLK_EN                (1 << 17)
+#define CKCTL_6368_IPSEC_CLK_EN                (1 << 18)
 
 #define CKCTL_6368_ALL_SAFE_EN         (CKCTL_6368_SWPKT_USB_EN |      \
                                        CKCTL_6368_SWPKT_SAR_EN |       \
index d11aa02a956a57ca41ff890dbe16bbdd0145db53..5447d9fc421941da85a2b0ce6bed2b865a4a8282 100644 (file)
 #define GIC_CPU_INT4           4 /* .                  */
 #define GIC_CPU_INT5           5 /* Core Interrupt 5   */
 
+/* MALTA GIC local interrupts */
+#define GIC_INT_TMR             (GIC_CPU_INT5)
+#define GIC_INT_PERFCTR         (GIC_CPU_INT5)
+
+/* GIC constants */
+/* Add 2 to convert non-eic hw int # to eic vector # */
+#define GIC_CPU_TO_VEC_OFFSET   (2)
+/* If we map an intr to pin X, GIC will actually generate vector X+1 */
+#define GIC_PIN_TO_VEC_OFFSET   (1)
+
 #define GIC_EXT_INTR(x)                x
 
 /* External Interrupts used for IPI */
index c9420aa97e3232dc8b96ccf2c960e6d0aa8f1f00..e71ff4c317f2d0bdd8df430b0f439286abb4559f 100644 (file)
@@ -48,7 +48,7 @@
 #define CP0_VPECONF0           $1, 2
 #define CP0_VPECONF1           $1, 3
 #define CP0_YQMASK             $1, 4
-#define CP0_VPESCHEDULE        $1, 5
+#define CP0_VPESCHEDULE                $1, 5
 #define CP0_VPESCHEFBK         $1, 6
 #define CP0_TCSTATUS           $2, 1
 #define CP0_TCBIND             $2, 2
index 5d33621b5658f9c46314f4fcc1d2d123eaaf83d5..4f8ddba8c360050703d6d760b5909e92944e8b23 100644 (file)
@@ -22,7 +22,7 @@ struct task_struct;
  * switch_to(n) should switch tasks to task nr n, first
  * checking that n isn't the current task, in which case it does nothing.
  */
-extern asmlinkage void *resume(void *last, void *next, void *next_ti);
+extern asmlinkage void *resume(void *last, void *next, void *next_ti, u32 __usedfpu);
 
 extern unsigned int ll_bit;
 extern struct task_struct *ll_task;
@@ -66,11 +66,13 @@ do {                                                                        \
 
 #define switch_to(prev, next, last)                                    \
 do {                                                                   \
+       u32 __usedfpu;                                                  \
        __mips_mt_fpaff_switch_to(prev);                                \
        if (cpu_has_dsp)                                                \
                __save_dsp(prev);                                       \
        __clear_software_ll_bit();                                      \
-       (last) = resume(prev, next, task_thread_info(next));            \
+       __usedfpu = test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU);  \
+       (last) = resume(prev, next, task_thread_info(next), __usedfpu); \
 } while (0)
 
 #define finish_arch_switch(prev)                                       \
index e2eca7d1059800e22704b467ab4f94f955df27c0..ca97e0ecb64b5054195b7d271017fa2760b7d05a 100644 (file)
@@ -60,6 +60,8 @@ struct thread_info {
 register struct thread_info *__current_thread_info __asm__("$28");
 #define current_thread_info()  __current_thread_info
 
+#endif /* !__ASSEMBLY__ */
+
 /* thread information allocation */
 #if defined(CONFIG_PAGE_SIZE_4KB) && defined(CONFIG_32BIT)
 #define THREAD_SIZE_ORDER (1)
@@ -85,8 +87,6 @@ register struct thread_info *__current_thread_info __asm__("$28");
 
 #define STACK_WARN     (THREAD_SIZE / 8)
 
-#endif /* !__ASSEMBLY__ */
-
 #define PREEMPT_ACTIVE         0x10000000
 
 /*
index 6ae7ce4ac63eb9b6a65ecf8ae0a49093579ae597..f4630e1082ab676a96e052e504995e86716be012 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) xxxx  the Anonymous
  * Copyright (C) 1994 - 2006 Ralf Baechle
  * Copyright (C) 2003, 2004  Maciej W. Rozycki
- * Copyright (C) 2001, 2004  MIPS Inc.
+ * Copyright (C) 2001, 2004, 2011, 2012  MIPS Technologies, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -199,6 +199,7 @@ void __init check_wait(void)
                cpu_wait = rm7k_wait_irqoff;
                break;
 
+       case CPU_M14KC:
        case CPU_24K:
        case CPU_34K:
        case CPU_1004K:
@@ -810,6 +811,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_5KC;
                __cpu_name[cpu] = "MIPS 5Kc";
                break;
+       case PRID_IMP_5KE:
+               c->cputype = CPU_5KE;
+               __cpu_name[cpu] = "MIPS 5KE";
+               break;
        case PRID_IMP_20KC:
                c->cputype = CPU_20KC;
                __cpu_name[cpu] = "MIPS 20Kc";
@@ -831,6 +836,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_74K;
                __cpu_name[cpu] = "MIPS 74Kc";
                break;
+       case PRID_IMP_M14KC:
+               c->cputype = CPU_M14KC;
+               __cpu_name[cpu] = "MIPS M14Kc";
+               break;
        case PRID_IMP_1004K:
                c->cputype = CPU_1004K;
                __cpu_name[cpu] = "MIPS 1004Kc";
index 57ba13edb03af10da20a9ce936645902d9f562c1..3fc1691110dc52f82e8ec1271054c1411c122658 100644 (file)
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05 by Ralf Baechle
+ * Copyright (C) 1996, 97, 98, 99, 2000, 01, 03, 04, 05, 12 by Ralf Baechle
  * Copyright (C) 1999, 2000, 01 Silicon Graphics, Inc.
  */
 #include <linux/interrupt.h>
@@ -34,6 +34,12 @@ EXPORT_SYMBOL(memmove);
 
 EXPORT_SYMBOL(kernel_thread);
 
+/*
+ * Functions that operate on entire pages.  Mostly used by memory management.
+ */
+EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(copy_page);
+
 /*
  * Userspace access stuff.
  */
index ce89c806170846a1ea2bbcf027598fae11028648..0441f54b2a6acc9ab27a0d229c1465a8e0fa5975 100644 (file)
@@ -31,7 +31,7 @@
 
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
- *                     struct thread_info *next_ti)
+ *                     struct thread_info *next_ti, int usedfpu)
  */
        .align  7
        LEAF(resume)
index f29099b104c497e5cb4b4a3d368a801fc6c60d05..eb5e394a4650bbe9f0814e51bc00e1b8523c57f1 100644 (file)
@@ -162,11 +162,6 @@ static unsigned int counters_total_to_per_cpu(unsigned int counters)
        return counters >> vpe_shift();
 }
 
-static unsigned int counters_per_cpu_to_total(unsigned int counters)
-{
-       return counters << vpe_shift();
-}
-
 #else /* !CONFIG_MIPS_MT_SMP */
 #define vpe_id()       0
 
index 293898391e674bd0979f87918a019b3a377d575d..9c51be5a163a9249efa3bd74f12be62b64eba923 100644 (file)
@@ -43,7 +43,7 @@
 
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
- *                     struct thread_info *next_ti)
+ *                     struct thread_info *next_ti, int usedfpu)
  */
 LEAF(resume)
        mfc0    t1, CP0_STATUS
@@ -51,18 +51,9 @@ LEAF(resume)
        cpu_save_nonscratch a0
        sw      ra, THREAD_REG31(a0)
 
-       /*
-        * check if we need to save FPU registers
-        */
-       lw      t3, TASK_THREAD_INFO(a0)
-       lw      t0, TI_FLAGS(t3)
-       li      t1, _TIF_USEDFPU
-       and     t2, t0, t1
-       beqz    t2, 1f
-       nor     t1, zero, t1
+       beqz    a3, 1f
 
-       and     t0, t0, t1
-       sw      t0, TI_FLAGS(t3)
+       PTR_L   t3, TASK_THREAD_INFO(a0)
 
        /*
         * clear saved user stack CU1 bit
index 9414f935446968069ec4f22daed1ae19b0799fb7..42d2a3938420df28e64d1f016459529b13991b7e 100644 (file)
@@ -41,7 +41,7 @@
 
 /*
  * task_struct *resume(task_struct *prev, task_struct *next,
- *                     struct thread_info *next_ti)
+ *                     struct thread_info *next_ti, int usedfpu)
  */
        .align  5
        LEAF(resume)
        /*
         * check if we need to save FPU registers
         */
-       PTR_L   t3, TASK_THREAD_INFO(a0)
-       LONG_L  t0, TI_FLAGS(t3)
-       li      t1, _TIF_USEDFPU
-       and     t2, t0, t1
-       beqz    t2, 1f
-       nor     t1, zero, t1
 
-       and     t0, t0, t1
-       LONG_S  t0, TI_FLAGS(t3)
+       beqz    a3, 1f
 
+       PTR_L   t3, TASK_THREAD_INFO(a0)
        /*
         * clear saved user stack CU1 bit
         */
index 3046e2986006b448c884bbb7355a676cc63e6ad9..8e393b8443f7ae4aa8c4b8a99eb1f689e49957c1 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/reboot.h>
@@ -197,13 +196,6 @@ static void bmips_init_secondary(void)
 
        write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
 #endif
-
-       /* make sure there won't be a timer interrupt for a little while */
-       write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
-
-       irq_enable_hazard();
-       set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE);
-       irq_enable_hazard();
 }
 
 /*
@@ -212,6 +204,13 @@ static void bmips_init_secondary(void)
 static void bmips_smp_finish(void)
 {
        pr_info("SMP: CPU%d is running\n", smp_processor_id());
+
+       /* make sure there won't be a timer interrupt for a little while */
+       write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ);
+
+       irq_enable_hazard();
+       set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ1 | IE_IRQ5 | ST0_IE);
+       irq_enable_hazard();
 }
 
 /*
index 48650c8180401aeb1ce1c3f2713471d9c6e45536..1268392f1d2786bc3abb91fdb9a88ad84fa85ec9 100644 (file)
@@ -122,13 +122,21 @@ asmlinkage __cpuinit void start_secondary(void)
 
        notify_cpu_starting(cpu);
 
-       mp_ops->smp_finish();
+       set_cpu_online(cpu, true);
+
        set_cpu_sibling_map(cpu);
 
        cpu_set(cpu, cpu_callin_map);
 
        synchronise_count_slave();
 
+       /*
+        * irq will be enabled in ->smp_finish(), enabling it too early
+        * is dangerous.
+        */
+       WARN_ON_ONCE(!irqs_disabled());
+       mp_ops->smp_finish();
+
        cpu_idle();
 }
 
@@ -196,8 +204,6 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
        while (!cpu_isset(cpu, cpu_callin_map))
                udelay(100);
 
-       set_cpu_online(cpu, true);
-
        return 0;
 }
 
index f5dd38f1d0152b49b13c971c59fde0cd218cb93e..15b5f3cfd20c48b9424dd5364d29cf1aeff77d4a 100644 (file)
@@ -322,7 +322,7 @@ int __init smtc_build_cpu_map(int start_cpu_slot)
 
 /*
  * Common setup before any secondaries are started
- * Make sure all CPU's are in a sensible state before we boot any of the
+ * Make sure all CPUs are in a sensible state before we boot any of the
  * secondaries.
  *
  * For MIPS MT "SMTC" operation, we set up all TCs, spread as evenly
@@ -340,12 +340,12 @@ static void smtc_tc_setup(int vpe, int tc, int cpu)
        /*
         * TCContext gets an offset from the base of the IPIQ array
         * to be used in low-level code to detect the presence of
-        * an active IPI queue
+        * an active IPI queue.
         */
        write_tc_c0_tccontext((sizeof(struct smtc_ipi_q) * cpu) << 16);
        /* Bind tc to vpe */
        write_tc_c0_tcbind(vpe);
-       /* In general, all TCs should have the same cpu_data indications */
+       /* In general, all TCs should have the same cpu_data indications. */
        memcpy(&cpu_data[cpu], &cpu_data[0], sizeof(struct cpuinfo_mips));
        /* For 34Kf, start with TC/CPU 0 as sole owner of single FPU context */
        if (cpu_data[0].cputype == CPU_34K ||
@@ -358,8 +358,8 @@ static void smtc_tc_setup(int vpe, int tc, int cpu)
 }
 
 /*
- * Tweak to get Count registes in as close a sync as possible.
- * Value seems good for 34K-class cores.
+ * Tweak to get Count registes in as close a sync as possible.  The
+ * value seems good for 34K-class cores.
  */
 
 #define CP0_SKEW 8
@@ -615,7 +615,6 @@ void __cpuinit smtc_boot_secondary(int cpu, struct task_struct *idle)
 
 void smtc_init_secondary(void)
 {
-       local_irq_enable();
 }
 
 void smtc_smp_finish(void)
@@ -631,6 +630,8 @@ void smtc_smp_finish(void)
        if (cpu > 0 && (cpu_data[cpu].vpe_id != cpu_data[cpu - 1].vpe_id))
                write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ);
 
+       local_irq_enable();
+
        printk("TC %d going on-line as CPU %d\n",
                cpu_data[smp_processor_id()].tc_id, smp_processor_id());
 }
index 99f913c8d7a6eb3e4db9ac2f7b8def493a4e5e5e..842d55e411fd396479b611ba0a1c0c2af2d4cb92 100644 (file)
@@ -111,7 +111,6 @@ void __cpuinit synchronise_count_master(void)
 void __cpuinit synchronise_count_slave(void)
 {
        int i;
-       unsigned long flags;
        unsigned int initcount;
        int ncpus;
 
@@ -123,8 +122,6 @@ void __cpuinit synchronise_count_slave(void)
        return;
 #endif
 
-       local_irq_save(flags);
-
        /*
         * Not every cpu is online at the time this gets called,
         * so we first wait for the master to say everyone is ready
@@ -154,7 +151,5 @@ void __cpuinit synchronise_count_slave(void)
        }
        /* Arrange for an interrupt in a short while */
        write_c0_compare(read_c0_count() + COUNTON);
-
-       local_irq_restore(flags);
 }
 #undef NR_LOOPS
index 2d0c2a277f525b5b89b89500a5153c9032ed4ce3..c3c29354370345ae74c25dce1e4e7e7da9263316 100644 (file)
@@ -132,6 +132,9 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs)
        unsigned long ra = regs->regs[31];
        unsigned long pc = regs->cp0_epc;
 
+       if (!task)
+               task = current;
+
        if (raw_show_trace || !__kernel_text_address(pc)) {
                show_raw_backtrace(sp);
                return;
@@ -1249,6 +1252,7 @@ static inline void parity_protection_init(void)
                break;
 
        case CPU_5KC:
+       case CPU_5KE:
                write_c0_ecc(0x80000000);
                back_to_back_c0_hazard();
                /* Set the PE bit (bit 31) in the c0_errctl register. */
@@ -1498,6 +1502,7 @@ extern void flush_tlb_handlers(void);
  * Timer interrupt
  */
 int cp0_compare_irq;
+EXPORT_SYMBOL_GPL(cp0_compare_irq);
 int cp0_compare_irq_shift;
 
 /*
@@ -1597,7 +1602,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu)
                        cp0_perfcount_irq = -1;
        } else {
                cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
-               cp0_compare_irq_shift = cp0_compare_irq;
+               cp0_compare_irq_shift = CP0_LEGACY_PERFCNT_IRQ;
                cp0_perfcount_irq = -1;
        }
 
index 924da5eb7031498ea93dc050a7492aa78f5bb0ec..df243a64f4305305564ec1e1e5b7f68c4c6e55ad 100644 (file)
@@ -1,5 +1,6 @@
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
+#include <asm/thread_info.h>
 #include <asm-generic/vmlinux.lds.h>
 
 #undef mips
@@ -72,7 +73,7 @@ SECTIONS
        .data : {       /* Data */
                . = . + DATAOFFSET;             /* for CONFIG_MAPPED_KERNEL */
 
-               INIT_TASK_DATA(PAGE_SIZE)
+               INIT_TASK_DATA(THREAD_SIZE)
                NOSAVE_DATA
                CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
                READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
index 4aa20280613ea3954db6e7925cc2fead924b0b78..fd6203f14f1fbfb8e608606235f77f3dd3113272 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 obj-y                          += cache.o dma-default.o extable.o fault.o \
-                                  gup.o init.o mmap.o page.o tlbex.o \
-                                  tlbex-fault.o uasm.o
+                                  gup.o init.o mmap.o page.o page-funcs.o \
+                                  tlbex.o tlbex-fault.o uasm.o
 
 obj-$(CONFIG_32BIT)            += ioremap.o pgtable-32.o
 obj-$(CONFIG_64BIT)            += pgtable-64.o
index 5109be96d98d099ec8509dd1de6a9048f5c4b82d..f092c265dc6360a89403ac62c184b7f4ab417437 100644 (file)
@@ -977,7 +977,7 @@ static void __cpuinit probe_pcache(void)
                        c->icache.linesz = 2 << lsize;
                else
                        c->icache.linesz = lsize;
-               c->icache.sets = 64 << ((config1 >> 22) & 7);
+               c->icache.sets = 32 << (((config1 >> 22) + 1) & 7);
                c->icache.ways = 1 + ((config1 >> 16) & 7);
 
                icache_size = c->icache.sets *
@@ -997,7 +997,7 @@ static void __cpuinit probe_pcache(void)
                        c->dcache.linesz = 2 << lsize;
                else
                        c->dcache.linesz= lsize;
-               c->dcache.sets = 64 << ((config1 >> 13) & 7);
+               c->dcache.sets = 32 << (((config1 >> 13) + 1) & 7);
                c->dcache.ways = 1 + ((config1 >> 7) & 7);
 
                dcache_size = c->dcache.sets *
@@ -1051,6 +1051,7 @@ static void __cpuinit probe_pcache(void)
        case CPU_R14000:
                break;
 
+       case CPU_M14KC:
        case CPU_24K:
        case CPU_34K:
        case CPU_74K:
diff --git a/arch/mips/mm/page-funcs.S b/arch/mips/mm/page-funcs.S
new file mode 100644 (file)
index 0000000..48a6b38
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ * Micro-assembler generated clear_page/copy_page functions.
+ *
+ * Copyright (C) 2012  MIPS Technologies, Inc.
+ * Copyright (C) 2012  Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+#define cpu_clear_page_function_name   clear_page_cpu
+#define cpu_copy_page_function_name    copy_page_cpu
+#else
+#define cpu_clear_page_function_name   clear_page
+#define cpu_copy_page_function_name    copy_page
+#endif
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache:            0x058 bytes
+ * R4600 v1.7:                         0x05c bytes
+ * R4600 v2.0:                         0x060 bytes
+ * With prefetching, 16 word strides   0x120 bytes
+ */
+EXPORT(__clear_page_start)
+LEAF(cpu_clear_page_function_name)
+1:     j       1b              /* Dummy, will be replaced. */
+       .space 288
+END(cpu_clear_page_function_name)
+EXPORT(__clear_page_end)
+
+/*
+ * Maximum sizes:
+ *
+ * R4000 128 bytes S-cache:            0x11c bytes
+ * R4600 v1.7:                         0x080 bytes
+ * R4600 v2.0:                         0x07c bytes
+ * With prefetching, 16 word strides   0x540 bytes
+ */
+EXPORT(__copy_page_start)
+LEAF(cpu_copy_page_function_name)
+1:     j       1b              /* Dummy, will be replaced. */
+       .space 1344
+END(cpu_copy_page_function_name)
+EXPORT(__copy_page_end)
index cc0b626858b3d0b6e34e5e510004083ce7bfba24..98f530e182163146ee4bba570edc2c3013236f31 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2003, 04, 05 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2007  Maciej W. Rozycki
  * Copyright (C) 2008  Thiemo Seufer
+ * Copyright (C) 2012  MIPS Technologies, Inc.
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -71,45 +72,6 @@ static struct uasm_reloc __cpuinitdata relocs[5];
 #define cpu_is_r4600_v1_x()    ((read_c0_prid() & 0xfffffff0) == 0x00002010)
 #define cpu_is_r4600_v2_x()    ((read_c0_prid() & 0xfffffff0) == 0x00002020)
 
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache:            0x058 bytes
- * R4600 v1.7:                         0x05c bytes
- * R4600 v2.0:                         0x060 bytes
- * With prefetching, 16 word strides   0x120 bytes
- */
-
-static u32 clear_page_array[0x120 / 4];
-
-#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
-void clear_page_cpu(void *page) __attribute__((alias("clear_page_array")));
-#else
-void clear_page(void *page) __attribute__((alias("clear_page_array")));
-#endif
-
-EXPORT_SYMBOL(clear_page);
-
-/*
- * Maximum sizes:
- *
- * R4000 128 bytes S-cache:            0x11c bytes
- * R4600 v1.7:                         0x080 bytes
- * R4600 v2.0:                         0x07c bytes
- * With prefetching, 16 word strides   0x540 bytes
- */
-static u32 copy_page_array[0x540 / 4];
-
-#ifdef CONFIG_SIBYTE_DMA_PAGEOPS
-void
-copy_page_cpu(void *to, void *from) __attribute__((alias("copy_page_array")));
-#else
-void copy_page(void *to, void *from) __attribute__((alias("copy_page_array")));
-#endif
-
-EXPORT_SYMBOL(copy_page);
-
-
 static int pref_bias_clear_store __cpuinitdata;
 static int pref_bias_copy_load __cpuinitdata;
 static int pref_bias_copy_store __cpuinitdata;
@@ -282,10 +244,15 @@ static inline void __cpuinit build_clear_pref(u32 **buf, int off)
                }
 }
 
+extern u32 __clear_page_start;
+extern u32 __clear_page_end;
+extern u32 __copy_page_start;
+extern u32 __copy_page_end;
+
 void __cpuinit build_clear_page(void)
 {
        int off;
-       u32 *buf = (u32 *)&clear_page_array;
+       u32 *buf = &__clear_page_start;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
        int i;
@@ -356,17 +323,17 @@ void __cpuinit build_clear_page(void)
        uasm_i_jr(&buf, RA);
        uasm_i_nop(&buf);
 
-       BUG_ON(buf > clear_page_array + ARRAY_SIZE(clear_page_array));
+       BUG_ON(buf > &__clear_page_end);
 
        uasm_resolve_relocs(relocs, labels);
 
        pr_debug("Synthesized clear page handler (%u instructions).\n",
-                (u32)(buf - clear_page_array));
+                (u32)(buf - &__clear_page_start));
 
        pr_debug("\t.set push\n");
        pr_debug("\t.set noreorder\n");
-       for (i = 0; i < (buf - clear_page_array); i++)
-               pr_debug("\t.word 0x%08x\n", clear_page_array[i]);
+       for (i = 0; i < (buf - &__clear_page_start); i++)
+               pr_debug("\t.word 0x%08x\n", (&__clear_page_start)[i]);
        pr_debug("\t.set pop\n");
 }
 
@@ -427,7 +394,7 @@ static inline void build_copy_store_pref(u32 **buf, int off)
 void __cpuinit build_copy_page(void)
 {
        int off;
-       u32 *buf = (u32 *)&copy_page_array;
+       u32 *buf = &__copy_page_start;
        struct uasm_label *l = labels;
        struct uasm_reloc *r = relocs;
        int i;
@@ -595,21 +562,23 @@ void __cpuinit build_copy_page(void)
        uasm_i_jr(&buf, RA);
        uasm_i_nop(&buf);
 
-       BUG_ON(buf > copy_page_array + ARRAY_SIZE(copy_page_array));
+       BUG_ON(buf > &__copy_page_end);
 
        uasm_resolve_relocs(relocs, labels);
 
        pr_debug("Synthesized copy page handler (%u instructions).\n",
-                (u32)(buf - copy_page_array));
+                (u32)(buf - &__copy_page_start));
 
        pr_debug("\t.set push\n");
        pr_debug("\t.set noreorder\n");
-       for (i = 0; i < (buf - copy_page_array); i++)
-               pr_debug("\t.word 0x%08x\n", copy_page_array[i]);
+       for (i = 0; i < (buf - &__copy_page_start); i++)
+               pr_debug("\t.word 0x%08x\n", (&__copy_page_start)[i]);
        pr_debug("\t.set pop\n");
 }
 
 #ifdef CONFIG_SIBYTE_DMA_PAGEOPS
+extern void clear_page_cpu(void *page);
+extern void copy_page_cpu(void *to, void *from);
 
 /*
  * Pad descriptors to cacheline, since each is exclusively owned by a
index 0bc485b3cd606de49e62aff00c9fe611e3a90540..03eb0ef9158047b023ee87d8d5d0e45c67c1583f 100644 (file)
@@ -9,6 +9,7 @@
  * Copyright (C) 2005, 2007, 2008, 2009  Maciej W. Rozycki
  * Copyright (C) 2006  Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 2008, 2009 Cavium Networks, Inc.
+ * Copyright (C) 2011  MIPS Technologies, Inc.
  *
  * ... and the days got worse and worse and now you see
  * I've gone completly out of my mind.
@@ -494,6 +495,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
        case CPU_R14000:
        case CPU_4KC:
        case CPU_4KEC:
+       case CPU_M14KC:
        case CPU_SB1:
        case CPU_SB1A:
        case CPU_4KSC:
index bf80921f2f56c0b145e698fa2c673ff49c7c0636..284dea54faf5a9f629e9d2cab18121cc5db328c6 100644 (file)
@@ -241,8 +241,9 @@ void __init mips_pcibios_init(void)
                return;
        }
 
-       if (controller->io_resource->start < 0x00001000UL)      /* FIXME */
-               controller->io_resource->start = 0x00001000UL;
+       /* Change start address to avoid conflicts with ACPI and SMB devices */
+       if (controller->io_resource->start < 0x00002000UL)
+               controller->io_resource->start = 0x00002000UL;
 
        iomem_resource.end &= 0xfffffffffULL;                   /* 64 GB */
        ioport_resource.end = controller->io_resource->end;
@@ -253,7 +254,7 @@ void __init mips_pcibios_init(void)
 }
 
 /* Enable PCI 2.1 compatibility in PIIX4 */
-static void __init quirk_dlcsetup(struct pci_dev *dev)
+static void __devinit quirk_dlcsetup(struct pci_dev *dev)
 {
        u8 odlc, ndlc;
        (void) pci_read_config_byte(dev, 0x82, &odlc);
index b7f37d4982fab27b91213a83be7a178626b694cb..2e28f653f66d1b582b9d0ca89c389aaaa1b18ca8 100644 (file)
@@ -111,7 +111,7 @@ static void __init pci_clock_check(void)
        unsigned int __iomem *jmpr_p =
                (unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int));
        int jmpr = (__raw_readl(jmpr_p) >> 2) & 0x07;
-       static const int pciclocks[] __initdata = {
+       static const int pciclocks[] __initconst = {
                33, 20, 25, 30, 12, 16, 37, 10
        };
        int pciclock = pciclocks[jmpr];
index acb677a1227cc043a364b8938e78d7bd911c64d3..b3df7c2aad1e144fe8be92584272b14aed53973f 100644 (file)
@@ -82,8 +82,10 @@ void __init prom_free_prom_memory(void)
 
 void xlp_mmu_init(void)
 {
+       /* enable extended TLB and Large Fixed TLB */
        write_c0_config6(read_c0_config6() | 0x24);
-       current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
+
+       /* set page mask of Fixed TLB in config7 */
        write_c0_config7(PM_DEFAULT_MASK >>
                (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2)));
 }
@@ -100,6 +102,10 @@ void __init prom_init(void)
        nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1));
 #ifdef CONFIG_SMP
        nlm_wakeup_secondary_cpus(0xffffffff);
+
+       /* update TLB size after waking up threads */
+       current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
+
        register_smp_ops(&nlm_smp_ops);
 #endif
 }
index d1f2d4c52d42d3a0e1e92f5605d81632eefc8aa6..b6e378211a2c940021fb2e7befb342b90b1b1777 100644 (file)
@@ -78,6 +78,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 
        switch (current_cpu_type()) {
        case CPU_5KC:
+       case CPU_M14KC:
        case CPU_20KC:
        case CPU_24K:
        case CPU_25KF:
index baba3bcaa3c28100067a39d9e1a1132a5a8d02b4..4d80a856048d19261e3af077ff1ff5344b3b26d2 100644 (file)
@@ -322,6 +322,10 @@ static int __init mipsxx_init(void)
 
        op_model_mipsxx_ops.num_counters = counters;
        switch (current_cpu_type()) {
+       case CPU_M14KC:
+               op_model_mipsxx_ops.cpu_type = "mips/M14Kc";
+               break;
+
        case CPU_20KC:
                op_model_mipsxx_ops.cpu_type = "mips/20K";
                break;
index d5d4c018fb04c03f4ef6b1d26d05fd263ad4835e..0857ab8c3919750feb164b3649f60df502290312 100644 (file)
@@ -48,7 +48,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
        return 0;
 }
 
-static void __init loongson2e_nec_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
@@ -60,7 +60,7 @@ static void __init loongson2e_nec_fixup(struct pci_dev *pdev)
        pci_write_config_dword(pdev, 0xe4, 1 << 5);
 }
 
-static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func0_fixup(struct pci_dev *pdev)
 {
        unsigned char c;
 
@@ -135,7 +135,7 @@ static void __init loongson2e_686b_func0_fixup(struct pci_dev *pdev)
        printk(KERN_INFO"via686b fix: ISA bridge done\n");
 }
 
-static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func1_fixup(struct pci_dev *pdev)
 {
        printk(KERN_INFO"via686b fix: IDE\n");
 
@@ -168,19 +168,19 @@ static void __init loongson2e_686b_func1_fixup(struct pci_dev *pdev)
        printk(KERN_INFO"via686b fix: IDE done\n");
 }
 
-static void __init loongson2e_686b_func2_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func2_fixup(struct pci_dev *pdev)
 {
        /* irq routing */
        pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 10);
 }
 
-static void __init loongson2e_686b_func3_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func3_fixup(struct pci_dev *pdev)
 {
        /* irq routing */
        pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 11);
 }
 
-static void __init loongson2e_686b_func5_fixup(struct pci_dev *pdev)
+static void __devinit loongson2e_686b_func5_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
        unsigned char c;
index 4b9768d5d72948b200d7431b4754fb7c21a27bc9..a7b917dcf604bde1ee359b20fb203356c0e4a84e 100644 (file)
@@ -96,21 +96,21 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 }
 
 /* CS5536 SPEC. fixup */
-static void __init loongson_cs5536_isa_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_isa_fixup(struct pci_dev *pdev)
 {
        /* the uart1 and uart2 interrupt in PIC is enabled as default */
        pci_write_config_dword(pdev, PCI_UART1_INT_REG, 1);
        pci_write_config_dword(pdev, PCI_UART2_INT_REG, 1);
 }
 
-static void __init loongson_cs5536_ide_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ide_fixup(struct pci_dev *pdev)
 {
        /* setting the mutex pin as IDE function */
        pci_write_config_dword(pdev, PCI_IDE_CFG_REG,
                               CS5536_IDE_FLASH_SIGNATURE);
 }
 
-static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_acc_fixup(struct pci_dev *pdev)
 {
        /* enable the AUDIO interrupt in PIC  */
        pci_write_config_dword(pdev, PCI_ACC_INT_REG, 1);
@@ -118,14 +118,14 @@ static void __init loongson_cs5536_acc_fixup(struct pci_dev *pdev)
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xc0);
 }
 
-static void __init loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
 {
        /* enable the OHCI interrupt in PIC */
        /* THE OHCI, EHCI, UDC, OTG are shared with interrupt in PIC */
        pci_write_config_dword(pdev, PCI_OHCI_INT_REG, 1);
 }
 
-static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
+static void __devinit loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
 {
        u32 hi, lo;
 
@@ -137,7 +137,7 @@ static void __init loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
        pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000);
 }
 
-static void __init loongson_nec_fixup(struct pci_dev *pdev)
+static void __devinit loongson_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
index 0f48498bc231b074f1ec8b401e9660b29bf37e5c..70073c98ed320dc6f88f457028c8b9cd094e93ab 100644 (file)
@@ -49,10 +49,10 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
        return 0;
 }
 
-static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
+static void __devinit malta_piix_func0_fixup(struct pci_dev *pdev)
 {
        unsigned char reg_val;
-       static int piixirqmap[16] __initdata = {  /* PIIX PIRQC[A:D] irq mappings */
+       static int piixirqmap[16] __devinitdata = {  /* PIIX PIRQC[A:D] irq mappings */
                0,  0,  0,  3,
                4,  5,  6,  7,
                0,  9, 10, 11,
@@ -83,7 +83,7 @@ static void __init malta_piix_func0_fixup(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
         malta_piix_func0_fixup);
 
-static void __init malta_piix_func1_fixup(struct pci_dev *pdev)
+static void __devinit malta_piix_func1_fixup(struct pci_dev *pdev)
 {
        unsigned char reg_val;
 
index e08f49cb6875abd65d50b7cb1cee964f816d96b7..8e4f8288eca2e2fcfc17bd615a26a5e0a6a152de 100644 (file)
 
 #include <asm/vr41xx/mpc30x.h>
 
-static const int internal_func_irqs[] __initdata = {
+static const int internal_func_irqs[] __initconst = {
        VRC4173_CASCADE_IRQ,
        VRC4173_AC97_IRQ,
        VRC4173_USB_IRQ,
 };
 
-static const int irq_tab_mpc30x[] __initdata = {
+static const int irq_tab_mpc30x[] __initconst = {
  [12] = VRC4173_PCMCIA1_IRQ,
  [13] = VRC4173_PCMCIA2_IRQ,
  [29] = MQ200_IRQ,
index f0bb9146e6c038424281cd45bb5b3ebc9dab0815..d02900a72916869dc39a03d0dd2075a5f8e85d82 100644 (file)
@@ -15,7 +15,7 @@
  * Set the BCM1250, etc. PCI host bridge's TRDY timeout
  * to the finite max.
  */
-static void __init quirk_sb1250_pci(struct pci_dev *dev)
+static void __devinit quirk_sb1250_pci(struct pci_dev *dev)
 {
        pci_write_config_byte(dev, 0x40, 0xff);
 }
@@ -25,7 +25,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
 /*
  * The BCM1250, etc. PCI/HT bridge reports as a host bridge.
  */
-static void __init quirk_sb1250_ht(struct pci_dev *dev)
+static void __devinit quirk_sb1250_ht(struct pci_dev *dev)
 {
        dev->class = PCI_CLASS_BRIDGE_PCI << 8;
 }
@@ -35,7 +35,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
 /*
  * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
  */
-static void __init quirk_sp1011(struct pci_dev *dev)
+static void __devinit quirk_sp1011(struct pci_dev *dev)
 {
        pci_write_config_byte(dev, 0x64, 0xff);
 }
index a1e7e6d80c8c718e9b532e5ccb8ff0e7bac9e164..bc13e29d2bb34d6f9a257322e222b943da533c1c 100644 (file)
@@ -495,7 +495,7 @@ irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id)
 }
 
 #ifdef CONFIG_TOSHIBA_FPCIB0
-static void __init tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
+static void __devinit tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
 {
        struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(dev->bus);
 
index 0fbe4c0c170a25f5af0bd0da083a14c47e82e5f7..fdc24440294c7028c6fdf7e2a655b896dbe60ef7 100644 (file)
@@ -212,7 +212,7 @@ static inline void pci_enable_swapping(struct pci_dev *dev)
        bridge->b_widget.w_tflush;      /* Flush */
 }
 
-static void __init pci_fixup_ioc3(struct pci_dev *d)
+static void __devinit pci_fixup_ioc3(struct pci_dev *d)
 {
        pci_disable_swapping(d);
 }
index ea453532a33c6dfc0eeb49659b2dc9036494713a..075d87acd12ac4158e090b7918250e958f0d8c05 100644 (file)
@@ -129,7 +129,7 @@ static int __devinit ltq_pci_startup(struct platform_device *pdev)
 
        /* setup reset gpio used by pci */
        reset_gpio = of_get_named_gpio(node, "gpio-reset", 0);
-       if (reset_gpio > 0)
+       if (gpio_is_valid(reset_gpio))
                devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset");
 
        /* enable auto-switching between PCI and EBU */
@@ -192,7 +192,7 @@ static int __devinit ltq_pci_startup(struct platform_device *pdev)
        ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
 
        /* toggle reset pin */
-       if (reset_gpio > 0) {
+       if (gpio_is_valid(reset_gpio)) {
                __gpio_set_value(reset_gpio, 0);
                wmb();
                mdelay(1);
index 1644805a6730db188bf9f26245c947551e8a4b5b..172af1cd58672e137924e88dae7f37dcf82393be 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/irq.h>
 #include <linux/irqdesc.h>
 #include <linux/console.h>
+#include <linux/pci_regs.h>
 
 #include <asm/io.h>
 
@@ -156,35 +157,55 @@ struct pci_controller nlm_pci_controller = {
        .io_offset      = 0x00000000UL,
 };
 
+/*
+ * The top level PCIe links on the XLS PCIe controller appear as
+ * bridges. Given a device, this function finds which link it is
+ * on.
+ */
+static struct pci_dev *xls_get_pcie_link(const struct pci_dev *dev)
+{
+       struct pci_bus *bus, *p;
+
+       /* Find the bridge on bus 0 */
+       bus = dev->bus;
+       for (p = bus->parent; p && p->number != 0; p = p->parent)
+               bus = p;
+
+       return p ? bus->self : NULL;
+}
+
 static int get_irq_vector(const struct pci_dev *dev)
 {
+       struct pci_dev *lnk;
+
        if (!nlm_chip_is_xls())
-               return  PIC_PCIX_IRQ;   /* for XLR just one IRQ*/
+               return  PIC_PCIX_IRQ;   /* for XLR just one IRQ */
 
        /*
         * For XLS PCIe, there is an IRQ per Link, find out which
         * link the device is on to assign interrupts
-       */
-       if (dev->bus->self == NULL)
+        */
+       lnk = xls_get_pcie_link(dev);
+       if (lnk == NULL)
                return 0;
 
-       switch  (dev->bus->self->devfn) {
-       case 0x0:
+       switch  (PCI_SLOT(lnk->devfn)) {
+       case 0:
                return PIC_PCIE_LINK0_IRQ;
-       case 0x8:
+       case 1:
                return PIC_PCIE_LINK1_IRQ;
-       case 0x10:
+       case 2:
                if (nlm_chip_is_xls_b())
                        return PIC_PCIE_XLSB0_LINK2_IRQ;
                else
                        return PIC_PCIE_LINK2_IRQ;
-       case 0x18:
+       case 3:
                if (nlm_chip_is_xls_b())
                        return PIC_PCIE_XLSB0_LINK3_IRQ;
                else
                        return PIC_PCIE_LINK3_IRQ;
        }
-       WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
+       WARN(1, "Unexpected devfn %d\n", lnk->devfn);
        return 0;
 }
 
@@ -202,7 +223,27 @@ void arch_teardown_msi_irq(unsigned int irq)
 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
        struct msi_msg msg;
+       struct pci_dev *lnk;
        int irq, ret;
+       u16 val;
+
+       /* MSI not supported on XLR */
+       if (!nlm_chip_is_xls())
+               return 1;
+
+       /*
+        * Enable MSI on the XLS PCIe controller bridge which was disabled
+        * at enumeration, the bridge MSI capability is at 0x50
+        */
+       lnk = xls_get_pcie_link(dev);
+       if (lnk == NULL)
+               return 1;
+
+       pci_read_config_word(lnk, 0x50 + PCI_MSI_FLAGS, &val);
+       if ((val & PCI_MSI_FLAGS_ENABLE) == 0) {
+               val |= PCI_MSI_FLAGS_ENABLE;
+               pci_write_config_word(lnk, 0x50 + PCI_MSI_FLAGS, val);
+       }
 
        irq = get_irq_vector(dev);
        if (irq <= 0)
@@ -327,7 +368,7 @@ static int __init pcibios_init(void)
                }
        } else {
                /* XLR PCI controller ACK */
-               irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
+               irq_set_handler_data(PIC_PCIX_IRQ, xlr_pci_ack);
        }
 
        return 0;
index b71fae231049dfa86d25f3e5fef2216d968faa17..5edab2bc6fc0c3314d5925d2197781a7f563b4df 100644 (file)
@@ -115,11 +115,11 @@ static void yos_send_ipi_mask(const struct cpumask *mask, unsigned int action)
  */
 static void __cpuinit yos_init_secondary(void)
 {
-       set_c0_status(ST0_CO | ST0_IE | ST0_IM);
 }
 
 static void __cpuinit yos_smp_finish(void)
 {
+       set_c0_status(ST0_CO | ST0_IM | ST0_IE);
 }
 
 /* Hook for after all CPUs are online */
index 0a170e0ffeaae4ea84e0d5bfe1480203e69524be..7773f3d956b0cdc914ab82cb7c2fd79664c558f8 100644 (file)
@@ -28,7 +28,7 @@
 
 #define CALLIOPE_ADDR(x)       (CALLIOPE_IO_BASE + (x))
 
-const struct register_map calliope_register_map __initdata = {
+const struct register_map calliope_register_map __initconst = {
        .eic_slow0_strt_add = {.phys = CALLIOPE_ADDR(0x800000)},
        .eic_cfg_bits = {.phys = CALLIOPE_ADDR(0x800038)},
        .eic_ready_status = {.phys = CALLIOPE_ADDR(0x80004c)},
index bbc0c122be5ee34c3ece4cb2fdee9ddf8efef384..da076db7b7ed2fd572d6429231b370e381a10e69 100644 (file)
@@ -28,7 +28,7 @@
 
 #define CRONUS_ADDR(x) (CRONUS_IO_BASE + (x))
 
-const struct register_map cronus_register_map __initdata = {
+const struct register_map cronus_register_map __initconst = {
        .eic_slow0_strt_add = {.phys = CRONUS_ADDR(0x000000)},
        .eic_cfg_bits = {.phys = CRONUS_ADDR(0x000038)},
        .eic_ready_status = {.phys = CRONUS_ADDR(0x00004C)},
index 91dda682752ce25ece90b800a9103bb33cd80c86..47683b370e748da98a21860ce04424e8f8459b36 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/init.h>
 #include <asm/mach-powertv/asic.h>
 
-const struct register_map gaia_register_map __initdata = {
+const struct register_map gaia_register_map __initconst = {
        .eic_slow0_strt_add = {.phys = GAIA_IO_BASE + 0x000000},
        .eic_cfg_bits = {.phys = GAIA_IO_BASE + 0x000038},
        .eic_ready_status = {.phys = GAIA_IO_BASE + 0x00004C},
index 4a05bb096476a1ef7751f528c16d9ea9015827a9..6ff4b10f09dab4e4c3ba35242db83654315df0ab 100644 (file)
@@ -28,7 +28,7 @@
 
 #define ZEUS_ADDR(x)   (ZEUS_IO_BASE + (x))
 
-const struct register_map zeus_register_map __initdata = {
+const struct register_map zeus_register_map __initconst = {
        .eic_slow0_strt_add = {.phys = ZEUS_ADDR(0x000000)},
        .eic_cfg_bits = {.phys = ZEUS_ADDR(0x000038)},
        .eic_ready_status = {.phys = ZEUS_ADDR(0x00004c)},
index 682efb0c108d22576992c9f554653e9329916d3b..64eb71b1528032ea4af4f084fbbe9cf6c8d91216 100644 (file)
@@ -269,7 +269,7 @@ txx9_i8259_irq_setup(int irq)
        return err;
 }
 
-static void __init quirk_slc90e66_bridge(struct pci_dev *dev)
+static void __devinit quirk_slc90e66_bridge(struct pci_dev *dev)
 {
        int irq;        /* PCI/ISA Bridge interrupt */
        u8 reg_64;
index 55b79ef10028cbc3253685acbf0979edd6784d08..44251b974f1d96d4931e4704d9433163eb070962 100644 (file)
@@ -81,9 +81,6 @@ struct pt_regs {
 #define PTRACE_GETFPREGS          14
 #define PTRACE_SETFPREGS          15
 
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD     0x00000001
-
 #ifdef __KERNEL__
 
 #define user_mode(regs)                        (((regs)->epsw & EPSW_nSL) == EPSW_nSL)
index 08251d6f6b11015b5d8d265cba4fe88fc70e0f1c..ac519bbd42ffe32693a02d3f88ac5dbd21d426ff 100644 (file)
@@ -123,7 +123,7 @@ static inline unsigned long current_stack_pointer(void)
 }
 
 #ifndef CONFIG_KGDB
-void arch_release_thread_info(struct thread_info *ti)
+void arch_release_thread_info(struct thread_info *ti);
 #endif
 #define get_thread_info(ti)    get_task_struct((ti)->task)
 #define put_thread_info(ti)    put_task_struct((ti)->task)
index bd4e90dfe6c26d37c366abec8275a1d0d1e7b774..f8e66425cbf826f2f62aef4756869442a9ed5fdc 100644 (file)
@@ -11,7 +11,6 @@
 #ifndef _ASM_TIMEX_H
 #define _ASM_TIMEX_H
 
-#include <asm/hardirq.h>
 #include <unit/timex.h>
 
 #define TICK_SIZE (tick_nsec / 1000)
@@ -30,16 +29,6 @@ static inline cycles_t get_cycles(void)
 extern int init_clockevents(void);
 extern int init_clocksource(void);
 
-static inline void setup_jiffies_interrupt(int irq,
-                                          struct irqaction *action)
-{
-       u16 tmp;
-       setup_irq(irq, action);
-       set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
-       GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
-       tmp = GxICR(irq);
-}
-
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_TIMEX_H */
index 69cae0260786207d0c3b62fde6255f6b2f442995..ccce35e3e179150c87f5f94af2a2463333236a68 100644 (file)
@@ -70,6 +70,16 @@ static void event_handler(struct clock_event_device *dev)
 {
 }
 
+static inline void setup_jiffies_interrupt(int irq,
+                                          struct irqaction *action)
+{
+       u16 tmp;
+       setup_irq(irq, action);
+       set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
+       GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
+       tmp = GxICR(irq);
+}
+
 int __init init_clockevents(void)
 {
        struct clock_event_device *cd;
index a5ac755dd69f4acbc8c6d213c47c285b8af41098..2df440105a80f78e111f4f863261cbb7abab10ae 100644 (file)
@@ -9,6 +9,8 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#include <linux/irqreturn.h>
+
 struct clocksource;
 struct clock_event_device;
 
index 2381df83bd0064287110896a2cfb0a2678a8a046..35932a8de8b8d299fd7aaebcf31d56eb7c6db6d3 100644 (file)
@@ -170,9 +170,9 @@ mn10300_cpupic_setaffinity(struct irq_data *d, const struct cpumask *mask,
        case SC1TXIRQ:
 #ifdef CONFIG_MN10300_TTYSM1_TIMER12
        case TM12IRQ:
-#elif CONFIG_MN10300_TTYSM1_TIMER9
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER9)
        case TM9IRQ:
-#elif CONFIG_MN10300_TTYSM1_TIMER3
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
        case TM3IRQ:
 #endif /* CONFIG_MN10300_TTYSM1_TIMER12 */
 #endif /* CONFIG_MN10300_TTYSM1 */
index 6ab0bee2a54fd38efeccbaa683b4437f26406a34..4d584ae29ae1c1c2c53746ee3a6d1d9b78e7042a 100644 (file)
@@ -459,10 +459,11 @@ static int handle_signal(int sig,
        else
                ret = setup_frame(sig, ka, oldset, regs);
        if (ret)
-               return;
+               return ret;
 
        signal_delivered(sig, info, ka, regs,
-                                test_thread_flag(TIF_SINGLESTEP));
+                        test_thread_flag(TIF_SINGLESTEP));
+       return 0;
 }
 
 /*
index 090d35d369737599ec5c48f603ecba45c49797b3..e62c223e4c4594c3c06c762352d8e61a975e2d35 100644 (file)
@@ -876,9 +876,7 @@ static void __init smp_online(void)
 
        notify_cpu_starting(cpu);
 
-       ipi_call_lock();
        set_cpu_online(cpu, true);
-       ipi_call_unlock();
 
        local_irq_enable();
 }
index 94a9c6d53e1b890ea98d987628fad089d5fd012d..b900e5afa0aefae7969666fbb1cc9cf2e77d5994 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kdebug.h>
 #include <linux/bug.h>
 #include <linux/irq.h>
+#include <linux/export.h>
 #include <asm/processor.h>
 #include <linux/uaccess.h>
 #include <asm/io.h>
index 159acb02cfd4c16dcd1e91f9268b8d9dc6e74463..e244ebe637e15436f643a63e28217d9714321645 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/gfp.h>
+#include <linux/export.h>
 #include <asm/io.h>
 
 static unsigned long pci_sram_allocated = 0xbc000000;
index cc18fe7d8b90e2abc9061b430b7072386aeed0d8..c37f9832cf17d0a7cb5b8795766aa4c5feebd88e 100644 (file)
 #ifndef _ASM_UNIT_TIMEX_H
 #define _ASM_UNIT_TIMEX_H
 
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
 #include <asm/param.h>
index 43c246439413b8c5f70d9b50d79b733443e42882..53677694b16554af24b8c8262191673426ae193c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/timex.h>
 #include <asm/processor.h>
 #include <asm/intctl-regs.h>
index 758af30d1a16aad5b74820431e5abda8cc4ed1df..4cefc224f448d98843fe44c7e67631e98fa37466 100644 (file)
 #ifndef _ASM_UNIT_TIMEX_H
 #define _ASM_UNIT_TIMEX_H
 
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
 #include <asm/param.h>
index e1becd6b757132bd5664e82c5a676250ad660c3a..bc4adfaf815c1c2276c2f0f18bd84924b10c12d7 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/intctl-regs.h>
index ddb7ed0107065e19132dc242cd5b42b361c80f21..42f32db75087cc36b2f089ee6cd7c1bd3629e35b 100644 (file)
 #ifndef _ASM_UNIT_TIMEX_H
 #define _ASM_UNIT_TIMEX_H
 
-#ifndef __ASSEMBLY__
-#include <linux/irq.h>
-#endif /* __ASSEMBLY__ */
-
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
 #include <asm/param.h>
index a47828d31fe6d0c4f8f5197a348c8fce64a827e6..6266730efd615552f71a9e9409932c2298001167 100644 (file)
@@ -300,9 +300,7 @@ smp_cpu_init(int cpunum)
 
        notify_cpu_starting(cpunum);
 
-       ipi_call_lock();
        set_cpu_online(cpunum, true);
-       ipi_call_unlock();
 
        /* Initialise the idle task for this CPU */
        atomic_inc(&init_mm.mm_count);
index 6eb75b80488c8e613af39746fa2cbc8f96888b3c..0554ab062bdc555bdd1d28fb655519b8a39fcbe5 100644 (file)
@@ -86,8 +86,8 @@ static inline bool arch_irqs_disabled(void)
 }
 
 #ifdef CONFIG_PPC_BOOK3E
-#define __hard_irq_enable()    asm volatile("wrteei 1" : : : "memory");
-#define __hard_irq_disable()   asm volatile("wrteei 0" : : : "memory");
+#define __hard_irq_enable()    asm volatile("wrteei 1" : : : "memory")
+#define __hard_irq_disable()   asm volatile("wrteei 0" : : : "memory")
 #else
 #define __hard_irq_enable()    __mtmsrd(local_paca->kernel_msr | MSR_EE, 1)
 #define __hard_irq_disable()   __mtmsrd(local_paca->kernel_msr, 1)
@@ -125,6 +125,8 @@ static inline bool arch_irq_disabled_regs(struct pt_regs *regs)
        return !regs->softe;
 }
 
+extern bool prep_irq_for_idle(void);
+
 #else /* CONFIG_PPC64 */
 
 #define SET_MSR_EE(x)  mtmsr(x)
index 1b415027ec0e3c8031c18b5d1dabfeebff054fc5..1f017bb7a7cebfc3278fecfd7abe8f3dfaada107 100644 (file)
@@ -229,7 +229,7 @@ notrace void arch_local_irq_restore(unsigned long en)
         */
        if (unlikely(irq_happened != PACA_IRQ_HARD_DIS))
                __hard_irq_disable();
-#ifdef CONFIG_TRACE_IRQFLAG
+#ifdef CONFIG_TRACE_IRQFLAGS
        else {
                /*
                 * We should already be hard disabled here. We had bugs
@@ -286,6 +286,52 @@ void notrace restore_interrupts(void)
                __hard_irq_enable();
 }
 
+/*
+ * This is a helper to use when about to go into idle low-power
+ * when the latter has the side effect of re-enabling interrupts
+ * (such as calling H_CEDE under pHyp).
+ *
+ * You call this function with interrupts soft-disabled (this is
+ * already the case when ppc_md.power_save is called). The function
+ * will return whether to enter power save or just return.
+ *
+ * In the former case, it will have notified lockdep of interrupts
+ * being re-enabled and generally sanitized the lazy irq state,
+ * and in the latter case it will leave with interrupts hard
+ * disabled and marked as such, so the local_irq_enable() call
+ * in cpu_idle() will properly re-enable everything.
+ */
+bool prep_irq_for_idle(void)
+{
+       /*
+        * First we need to hard disable to ensure no interrupt
+        * occurs before we effectively enter the low power state
+        */
+       hard_irq_disable();
+
+       /*
+        * If anything happened while we were soft-disabled,
+        * we return now and do not enter the low power state.
+        */
+       if (lazy_irq_pending())
+               return false;
+
+       /* Tell lockdep we are about to re-enable */
+       trace_hardirqs_on();
+
+       /*
+        * Mark interrupts as soft-enabled and clear the
+        * PACA_IRQ_HARD_DIS from the pending mask since we
+        * are about to hard enable as well as a side effect
+        * of entering the low power state.
+        */
+       local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS;
+       local_paca->soft_enabled = 1;
+
+       /* Tell the caller to enter the low power state */
+       return true;
+}
+
 #endif /* CONFIG_PPC64 */
 
 int arch_show_interrupts(struct seq_file *p, int prec)
index e4cb34322de4aba848ce279b7792ea9d495dee5e..e1417c42155cd66dfe3532dfd8d7e4d3cd426233 100644 (file)
@@ -571,7 +571,6 @@ void __devinit start_secondary(void *unused)
        if (system_state == SYSTEM_RUNNING)
                vdso_data->processorCount++;
 #endif
-       ipi_call_lock();
        notify_cpu_starting(cpu);
        set_cpu_online(cpu, true);
        /* Update sibling maps */
@@ -601,7 +600,6 @@ void __devinit start_secondary(void *unused)
                of_node_put(np);
        }
        of_node_put(l2_cache);
-       ipi_call_unlock();
 
        local_irq_enable();
 
index a84aafce2a129e311a0943be0975db3823b88402..a1044f43becd380cdc7216e082fbf267b97a3fae 100644 (file)
@@ -810,7 +810,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        lwz     r3,VCORE_NAPPING_THREADS(r5)
        lwz     r4,VCPU_PTID(r9)
        li      r0,1
-       sldi    r0,r0,r4
+       sld     r0,r0,r4
        andc.   r3,r3,r0                /* no sense IPI'ing ourselves */
        beq     43f
        mulli   r4,r4,PACA_SIZE         /* get paca for thread 0 */
index 3ff9013d6e7914e59f2919f5ee5bf685ad7d7797..ee02b30878ed4bec733af6cbd9aa152eefe22d0f 100644 (file)
@@ -241,6 +241,7 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
        case H_PUT_TCE:
                return kvmppc_h_pr_put_tce(vcpu);
        case H_CEDE:
+               vcpu->arch.shared->msr |= MSR_EE;
                kvm_vcpu_block(vcpu);
                clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
                vcpu->stat.halt_wakeup++;
index 6e8f677f5646e4c66c801b3bc670c615e880c5b9..1e95556dc692e3702f2df518dd4e08e7770ae52e 100644 (file)
@@ -639,7 +639,7 @@ static void __init parse_drconf_memory(struct device_node *memory)
        unsigned int n, rc, ranges, is_kexec_kdump = 0;
        unsigned long lmb_size, base, size, sz;
        int nid;
-       struct assoc_arrays aa;
+       struct assoc_arrays aa = { .arrays = NULL };
 
        n = of_get_drconf_memory(memory, &dm);
        if (!n)
index efdacc829576582a0b4da52384f80ad62082cd4e..d17e98bc0c10d3ff0469cfa8af873f08d57abded 100644 (file)
@@ -42,11 +42,9 @@ static void cbe_power_save(void)
 {
        unsigned long ctrl, thread_switch_control;
 
-       /*
-        * We need to hard disable interrupts, the local_irq_enable() done by
-        * our caller upon return will hard re-enable.
-        */
-       hard_irq_disable();
+       /* Ensure our interrupt state is properly tracked */
+       if (!prep_irq_for_idle())
+               return;
 
        ctrl = mfspr(SPRN_CTRLF);
 
@@ -81,6 +79,9 @@ static void cbe_power_save(void)
         */
        ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
        mtspr(SPRN_CTRLT, ctrl);
+
+       /* Re-enable interrupts in MSR */
+       __hard_irq_enable();
 }
 
 static int cbe_system_reset_exception(struct pt_regs *regs)
index 66519d263da7fa250499abf9f4d7c288fe8e6432..d544d7816df3229780e4f2c58a1a28355c5c4aae 100644 (file)
@@ -317,28 +317,23 @@ out:
        return ret;
 }
 
-static int spufs_context_open(struct dentry *dentry, struct vfsmount *mnt)
+static int spufs_context_open(struct path *path)
 {
        int ret;
        struct file *filp;
 
        ret = get_unused_fd();
-       if (ret < 0) {
-               dput(dentry);
-               mntput(mnt);
-               goto out;
-       }
+       if (ret < 0)
+               return ret;
 
-       filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
+       filp = dentry_open(path, O_RDONLY, current_cred());
        if (IS_ERR(filp)) {
                put_unused_fd(ret);
-               ret = PTR_ERR(filp);
-               goto out;
+               return PTR_ERR(filp);
        }
 
        filp->f_op = &spufs_context_fops;
        fd_install(ret, filp);
-out:
        return ret;
 }
 
@@ -453,6 +448,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
        int affinity;
        struct spu_gang *gang;
        struct spu_context *neighbor;
+       struct path path = {.mnt = mnt, .dentry = dentry};
 
        ret = -EPERM;
        if ((flags & SPU_CREATE_NOSCHED) &&
@@ -495,11 +491,7 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
                        put_spu_context(neighbor);
        }
 
-       /*
-        * get references for dget and mntget, will be released
-        * in error path of *_open().
-        */
-       ret = spufs_context_open(dget(dentry), mntget(mnt));
+       ret = spufs_context_open(&path);
        if (ret < 0) {
                WARN_ON(spufs_rmdir(inode, dentry));
                if (affinity)
@@ -556,28 +548,27 @@ out:
        return ret;
 }
 
-static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt)
+static int spufs_gang_open(struct path *path)
 {
        int ret;
        struct file *filp;
 
        ret = get_unused_fd();
-       if (ret < 0) {
-               dput(dentry);
-               mntput(mnt);
-               goto out;
-       }
+       if (ret < 0)
+               return ret;
 
-       filp = dentry_open(dentry, mnt, O_RDONLY, current_cred());
+       /*
+        * get references for dget and mntget, will be released
+        * in error path of *_open().
+        */
+       filp = dentry_open(path, O_RDONLY, current_cred());
        if (IS_ERR(filp)) {
                put_unused_fd(ret);
-               ret = PTR_ERR(filp);
-               goto out;
+               return PTR_ERR(filp);
        }
 
        filp->f_op = &simple_dir_operations;
        fd_install(ret, filp);
-out:
        return ret;
 }
 
@@ -585,17 +576,14 @@ static int spufs_create_gang(struct inode *inode,
                        struct dentry *dentry,
                        struct vfsmount *mnt, umode_t mode)
 {
+       struct path path = {.mnt = mnt, .dentry = dentry};
        int ret;
 
        ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
        if (ret)
                goto out;
 
-       /*
-        * get references for dget and mntget, will be released
-        * in error path of *_open().
-        */
-       ret = spufs_gang_open(dget(dentry), mntget(mnt));
+       ret = spufs_gang_open(&path);
        if (ret < 0) {
                int err = simple_rmdir(inode, dentry);
                WARN_ON(err);
index e61483e8e96083b14d92430bae3f463947635fa8..c71be66bd5dc2ff3bc6e0b3309ad969859cb4b84 100644 (file)
@@ -99,15 +99,18 @@ out:
 static void check_and_cede_processor(void)
 {
        /*
-        * Interrupts are soft-disabled at this point,
-        * but not hard disabled. So an interrupt might have
-        * occurred before entering NAP, and would be potentially
-        * lost (edge events, decrementer events, etc...) unless
-        * we first hard disable then check.
+        * Ensure our interrupt state is properly tracked,
+        * also checks if no interrupt has occurred while we
+        * were soft-disabled
         */
-       hard_irq_disable();
-       if (!lazy_irq_pending())
+       if (prep_irq_for_idle()) {
                cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+               /* Ensure that H_CEDE returns with IRQs on */
+               if (WARN_ON(!(mfmsr() & MSR_EE)))
+                       __hard_irq_enable();
+#endif
+       }
 }
 
 static int dedicated_cede_loop(struct cpuidle_device *dev,
index 0f3ab06d222260c63d5866e6d6b7ab0ac643e761..eab3492a45c5c5244eca42d58354cf6d8a092836 100644 (file)
@@ -971,7 +971,7 @@ static int cpu_cmd(void)
                /* print cpus waiting or in xmon */
                printf("cpus stopped:");
                count = 0;
-               for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+               for_each_possible_cpu(cpu) {
                        if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
                                if (count == 0)
                                        printf(" %x", cpu);
index 15cca26ccb6c4ff1cbde51c60259a7ec95471718..8dca9c248ac793ea292ad4683e0057af5e9470d8 100644 (file)
@@ -717,9 +717,7 @@ static void __cpuinit smp_start_secondary(void *cpuvoid)
        init_cpu_vtimer();
        pfault_init();
        notify_cpu_starting(smp_processor_id());
-       ipi_call_lock();
        set_cpu_online(smp_processor_id(), true);
-       ipi_call_unlock();
        local_irq_enable();
        /* cpu_idle will call schedule for us */
        cpu_idle();
index e136d28d1d2ee5ad97f75866f9e9f3e4d118eba9..4d48f1436a63b72a34f8201ad8cb88416bc1a37d 100644 (file)
@@ -19,9 +19,20 @@ static inline u32 inl(unsigned long addr)
        return -1;
 }
 
-#define outb(x, y)     BUG()
-#define outw(x, y)     BUG()
-#define outl(x, y)     BUG()
+static inline void outb(unsigned char x, unsigned long port)
+{
+       BUG();
+}
+
+static inline void outw(unsigned short x, unsigned long port)
+{
+       BUG();
+}
+
+static inline void outl(unsigned int x, unsigned long port)
+{
+       BUG();
+}
 
 #define inb_p(addr)    inb(addr)
 #define inw_p(addr)    inw(addr)
index 8832c526cdf92d68cb8b59a48d2a05d8942ab181..c4a0336660dd102d6542b3f3a5721214439dce08 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/serial_core.h>
 #include <linux/io.h>
 #include <cpu/serial.h>
-#include <asm/gpio.h>
+#include <cpu/gpio.h>
 
 static void sh7720_sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
index f591598d92f67b165ebccdf4e3448a74df3c8cd2..781bcb10b8bd6f0ac34e1df6cf079dd0d3d59106 100644 (file)
@@ -103,8 +103,6 @@ void __cpuinit smp_callin(void)
        if (cheetah_pcache_forced_on)
                cheetah_enable_pcache();
 
-       local_irq_enable();
-
        callin_flag = 1;
        __asm__ __volatile__("membar #Sync\n\t"
                             "flush  %%g6" : : : "memory");
@@ -124,9 +122,8 @@ void __cpuinit smp_callin(void)
        while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
                rmb();
 
-       ipi_call_lock_irq();
        set_cpu_online(cpuid, true);
-       ipi_call_unlock_irq();
+       local_irq_enable();
 
        /* idle thread is expected to have preempt disabled */
        preempt_disable();
@@ -1308,9 +1305,7 @@ int __cpu_disable(void)
        mdelay(1);
        local_irq_disable();
 
-       ipi_call_lock();
        set_cpu_online(cpu, false);
-       ipi_call_unlock();
 
        cpu_map_rebuild();
 
index 9092ce8aa6b472b302ec31d514bb2da71fac3bfe..f8b74ca83b9257a245adaa6a03d05cdb75431c97 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/string.h>
+#include <asm/byteorder.h>
 #include <asm/backtrace.h>
 #include <asm/tile-desc.h>
 #include <arch/abi.h>
@@ -336,8 +337,12 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                                bytes_to_prefetch / sizeof(tile_bundle_bits);
                }
 
-               /* Decode the next bundle. */
-               bundle.bits = prefetched_bundles[next_bundle++];
+               /*
+                * Decode the next bundle.
+                * TILE always stores instruction bundles in little-endian
+                * mode, even when the chip is running in big-endian mode.
+                */
+               bundle.bits = le64_to_cpu(prefetched_bundles[next_bundle++]);
                bundle.num_insns =
                        parse_insn_tile(bundle.bits, pc, bundle.insns);
                num_info_ops = bt_get_info_ops(&bundle, info_operands);
index 84873fbe8f2769b0bfa22faaed187ae0919c523d..e686c5ac90be36bcf14d33019ac97bb5e46bc4ee 100644 (file)
@@ -198,17 +198,7 @@ void __cpuinit online_secondary(void)
 
        notify_cpu_starting(smp_processor_id());
 
-       /*
-        * We need to hold call_lock, so there is no inconsistency
-        * between the time smp_call_function() determines number of
-        * IPI recipients, and the time when the determination is made
-        * for which cpus receive the IPI. Holding this
-        * lock helps us to not include this cpu in a currently in progress
-        * smp_call_function().
-        */
-       ipi_call_lock();
        set_cpu_online(smp_processor_id(), 1);
-       ipi_call_unlock();
        __get_cpu_var(cpu_state) = CPU_ONLINE;
 
        /* Set up tile-specific state for this cpu. */
index 88e466b159dcac92a13d81b5919b0a5487d63830..43b39d61b538698229a23f654b7fb44a335187b3 100644 (file)
@@ -705,7 +705,6 @@ static void stack_proc(void *arg)
        struct task_struct *from = current, *to = arg;
 
        to->thread.saved_task = from;
-       rcu_switch_from(from);
        switch_to(from, to, from);
 }
 
index 1f25214345548584447a607676e61093301df8c8..b0c5276861ec8cc3b5713b6f83335746f812edde 100644 (file)
@@ -49,6 +49,9 @@ else
         KBUILD_AFLAGS += -m64
         KBUILD_CFLAGS += -m64
 
+       # Use -mpreferred-stack-boundary=3 if supported.
+       KBUILD_CFLAGS += $(call cc-option,-mno-sse -mpreferred-stack-boundary=3)
+
         # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
         cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
         cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
index 49331bedc158830ce55a9e24ba24933b94b5f7ee..70780689599acf830b322be2cad0f835ac2bac03 100644 (file)
@@ -75,23 +75,54 @@ static inline int alternatives_text_reserved(void *start, void *end)
 }
 #endif /* CONFIG_SMP */
 
+#define OLDINSTR(oldinstr)     "661:\n\t" oldinstr "\n662:\n"
+
+#define b_replacement(number)  "663"#number
+#define e_replacement(number)  "664"#number
+
+#define alt_slen "662b-661b"
+#define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f"
+
+#define ALTINSTR_ENTRY(feature, number)                                              \
+       " .long 661b - .\n"                             /* label           */ \
+       " .long " b_replacement(number)"f - .\n"        /* new instruction */ \
+       " .word " __stringify(feature) "\n"             /* feature bit     */ \
+       " .byte " alt_slen "\n"                         /* source len      */ \
+       " .byte " alt_rlen(number) "\n"                 /* replacement len */
+
+#define DISCARD_ENTRY(number)                          /* rlen <= slen */    \
+       " .byte 0xff + (" alt_rlen(number) ") - (" alt_slen ")\n"
+
+#define ALTINSTR_REPLACEMENT(newinstr, feature, number)        /* replacement */     \
+       b_replacement(number)":\n\t" newinstr "\n" e_replacement(number) ":\n\t"
+
 /* alternative assembly primitive: */
 #define ALTERNATIVE(oldinstr, newinstr, feature)                       \
-                                                                       \
-      "661:\n\t" oldinstr "\n662:\n"                                   \
-      ".section .altinstructions,\"a\"\n"                              \
-      "         .long 661b - .\n"                      /* label           */   \
-      "         .long 663f - .\n"                      /* new instruction */   \
-      "         .word " __stringify(feature) "\n"      /* feature bit     */   \
-      "         .byte 662b-661b\n"                     /* sourcelen       */   \
-      "         .byte 664f-663f\n"                     /* replacementlen  */   \
-      ".previous\n"                                                    \
-      ".section .discard,\"aw\",@progbits\n"                           \
-      "         .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */   \
-      ".previous\n"                                                    \
-      ".section .altinstr_replacement, \"ax\"\n"                       \
-      "663:\n\t" newinstr "\n664:\n"           /* replacement     */   \
-      ".previous"
+       OLDINSTR(oldinstr)                                              \
+       ".section .altinstructions,\"a\"\n"                             \
+       ALTINSTR_ENTRY(feature, 1)                                      \
+       ".previous\n"                                                   \
+       ".section .discard,\"aw\",@progbits\n"                          \
+       DISCARD_ENTRY(1)                                                \
+       ".previous\n"                                                   \
+       ".section .altinstr_replacement, \"ax\"\n"                      \
+       ALTINSTR_REPLACEMENT(newinstr, feature, 1)                      \
+       ".previous"
+
+#define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
+       OLDINSTR(oldinstr)                                              \
+       ".section .altinstructions,\"a\"\n"                             \
+       ALTINSTR_ENTRY(feature1, 1)                                     \
+       ALTINSTR_ENTRY(feature2, 2)                                     \
+       ".previous\n"                                                   \
+       ".section .discard,\"aw\",@progbits\n"                          \
+       DISCARD_ENTRY(1)                                                \
+       DISCARD_ENTRY(2)                                                \
+       ".previous\n"                                                   \
+       ".section .altinstr_replacement, \"ax\"\n"                      \
+       ALTINSTR_REPLACEMENT(newinstr1, feature1, 1)                    \
+       ALTINSTR_REPLACEMENT(newinstr2, feature2, 2)                    \
+       ".previous"
 
 /*
  * This must be included *after* the definition of ALTERNATIVE due to
@@ -139,6 +170,19 @@ static inline int alternatives_text_reserved(void *start, void *end)
        asm volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \
                : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input)
 
+/*
+ * Like alternative_call, but there are two features and respective functions.
+ * If CPU has feature2, function2 is used.
+ * Otherwise, if CPU has feature1, function1 is used.
+ * Otherwise, old function is used.
+ */
+#define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2,   \
+                          output, input...)                                  \
+       asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\
+               "call %P[new2]", feature2)                                    \
+               : output : [old] "i" (oldfunc), [new1] "i" (newfunc1),        \
+               [new2] "i" (newfunc2), ## input)
+
 /*
  * use this macro(s) if you need more than one output parameter
  * in alternative_io
index 49ad773f4b9f5f4631e4e5bed590c8d6356e4e0f..b3341e9cd8fdee3a25e7582563564d813594b6a3 100644 (file)
@@ -26,10 +26,31 @@ struct amd_l3_cache {
        u8       subcaches[4];
 };
 
+struct threshold_block {
+       unsigned int            block;
+       unsigned int            bank;
+       unsigned int            cpu;
+       u32                     address;
+       u16                     interrupt_enable;
+       bool                    interrupt_capable;
+       u16                     threshold_limit;
+       struct kobject          kobj;
+       struct list_head        miscj;
+};
+
+struct threshold_bank {
+       struct kobject          *kobj;
+       struct threshold_block  *blocks;
+
+       /* initialized to the number of CPUs on the node sharing this bank */
+       atomic_t                cpus;
+};
+
 struct amd_northbridge {
        struct pci_dev *misc;
        struct pci_dev *link;
        struct amd_l3_cache l3_cache;
+       struct threshold_bank *bank4;
 };
 
 struct amd_northbridge_info {
index eaff4790ed96c207d2ac51e0c89901707b5285ec..88093c1d44fd4c99064315eff9f169a8ef33235a 100644 (file)
@@ -306,7 +306,8 @@ struct apic {
        unsigned long (*check_apicid_used)(physid_mask_t *map, int apicid);
        unsigned long (*check_apicid_present)(int apicid);
 
-       void (*vector_allocation_domain)(int cpu, struct cpumask *retmask);
+       void (*vector_allocation_domain)(int cpu, struct cpumask *retmask,
+                                        const struct cpumask *mask);
        void (*init_apic_ldr)(void);
 
        void (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
@@ -331,9 +332,9 @@ struct apic {
        unsigned long (*set_apic_id)(unsigned int id);
        unsigned long apic_id_mask;
 
-       unsigned int (*cpu_mask_to_apicid)(const struct cpumask *cpumask);
-       unsigned int (*cpu_mask_to_apicid_and)(const struct cpumask *cpumask,
-                                              const struct cpumask *andmask);
+       int (*cpu_mask_to_apicid_and)(const struct cpumask *cpumask,
+                                     const struct cpumask *andmask,
+                                     unsigned int *apicid);
 
        /* ipi */
        void (*send_IPI_mask)(const struct cpumask *mask, int vector);
@@ -537,6 +538,11 @@ static inline const struct cpumask *default_target_cpus(void)
 #endif
 }
 
+static inline const struct cpumask *online_target_cpus(void)
+{
+       return cpu_online_mask;
+}
+
 DECLARE_EARLY_PER_CPU(u16, x86_bios_cpu_apicid);
 
 
@@ -586,21 +592,50 @@ static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
 
 #endif
 
-static inline unsigned int
-default_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static inline int
+flat_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
+                           const struct cpumask *andmask,
+                           unsigned int *apicid)
 {
-       return cpumask_bits(cpumask)[0] & APIC_ALL_CPUS;
+       unsigned long cpu_mask = cpumask_bits(cpumask)[0] &
+                                cpumask_bits(andmask)[0] &
+                                cpumask_bits(cpu_online_mask)[0] &
+                                APIC_ALL_CPUS;
+
+       if (likely(cpu_mask)) {
+               *apicid = (unsigned int)cpu_mask;
+               return 0;
+       } else {
+               return -EINVAL;
+       }
 }
 
-static inline unsigned int
+extern int
 default_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                              const struct cpumask *andmask)
+                              const struct cpumask *andmask,
+                              unsigned int *apicid);
+
+static inline void
+flat_vector_allocation_domain(int cpu, struct cpumask *retmask,
+                             const struct cpumask *mask)
 {
-       unsigned long mask1 = cpumask_bits(cpumask)[0];
-       unsigned long mask2 = cpumask_bits(andmask)[0];
-       unsigned long mask3 = cpumask_bits(cpu_online_mask)[0];
+       /* Careful. Some cpus do not strictly honor the set of cpus
+        * specified in the interrupt destination when using lowest
+        * priority interrupt delivery mode.
+        *
+        * In particular there was a hyperthreading cpu observed to
+        * deliver interrupts to the wrong hyperthread when only one
+        * hyperthread was specified in the interrupt desitination.
+        */
+       cpumask_clear(retmask);
+       cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
+}
 
-       return (unsigned int)(mask1 & mask2 & mask3);
+static inline void
+default_vector_allocation_domain(int cpu, struct cpumask *retmask,
+                                const struct cpumask *mask)
+{
+       cpumask_copy(retmask, cpumask_of(cpu));
 }
 
 static inline unsigned long default_check_apicid_used(physid_mask_t *map, int apicid)
index cc70c1c78ca47545bb7b927f878d3cb02275f142..75ce3f47d20412b5ab4e445e84978dc29ff7fc83 100644 (file)
@@ -4,9 +4,7 @@
 enum reboot_type {
        BOOT_TRIPLE = 't',
        BOOT_KBD = 'k',
-#ifdef CONFIG_X86_32
        BOOT_BIOS = 'b',
-#endif
        BOOT_ACPI = 'a',
        BOOT_EFI = 'e',
        BOOT_CF9 = 'p',
index dbe82a5c5eacde33f9cdf3791dfe159228f151b6..d3d74698dce9c09151a6421176224885454901df 100644 (file)
@@ -99,7 +99,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id)
                virtual_dma_residue += virtual_dma_count;
                virtual_dma_count = 0;
 #ifdef TRACE_FLPY_INT
-               printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
+               printk(KERN_DEBUG "count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
                       virtual_dma_count, virtual_dma_residue, calls, bytes,
                       dma_wait);
                calls = 0;
index db7c1f2709a270a03429ee1c9089209942647ff5..2da88c0cda1446f9e18a5ded4a64013e2a60dcbf 100644 (file)
@@ -313,8 +313,8 @@ struct kvm_pmu {
        u64 counter_bitmask[2];
        u64 global_ctrl_mask;
        u8 version;
-       struct kvm_pmc gp_counters[X86_PMC_MAX_GENERIC];
-       struct kvm_pmc fixed_counters[X86_PMC_MAX_FIXED];
+       struct kvm_pmc gp_counters[INTEL_PMC_MAX_GENERIC];
+       struct kvm_pmc fixed_counters[INTEL_PMC_MAX_FIXED];
        struct irq_work irq_work;
        u64 reprogram_pmi;
 };
index 084ef95274cd78ceb51b1ea7a208a7a5e486199a..813ed103f45edc0ac13042e8c18a922b909a8710 100644 (file)
@@ -115,8 +115,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr,
 
 extern unsigned long long native_read_tsc(void);
 
-extern int native_rdmsr_safe_regs(u32 regs[8]);
-extern int native_wrmsr_safe_regs(u32 regs[8]);
+extern int rdmsr_safe_regs(u32 regs[8]);
+extern int wrmsr_safe_regs(u32 regs[8]);
 
 static __always_inline unsigned long long __native_read_tsc(void)
 {
@@ -187,43 +187,6 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p)
        return err;
 }
 
-static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
-{
-       u32 gprs[8] = { 0 };
-       int err;
-
-       gprs[1] = msr;
-       gprs[7] = 0x9c5a203a;
-
-       err = native_rdmsr_safe_regs(gprs);
-
-       *p = gprs[0] | ((u64)gprs[2] << 32);
-
-       return err;
-}
-
-static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
-{
-       u32 gprs[8] = { 0 };
-
-       gprs[0] = (u32)val;
-       gprs[1] = msr;
-       gprs[2] = val >> 32;
-       gprs[7] = 0x9c5a203a;
-
-       return native_wrmsr_safe_regs(gprs);
-}
-
-static inline int rdmsr_safe_regs(u32 regs[8])
-{
-       return native_rdmsr_safe_regs(regs);
-}
-
-static inline int wrmsr_safe_regs(u32 regs[8])
-{
-       return native_wrmsr_safe_regs(regs);
-}
-
 #define rdtscl(low)                                            \
        ((low) = (u32)__native_read_tsc())
 
@@ -237,6 +200,8 @@ do {                                                        \
        (high) = (u32)(_l >> 32);                       \
 } while (0)
 
+#define rdpmcl(counter, val) ((val) = native_read_pmc(counter))
+
 #define rdtscp(low, high, aux)                                 \
 do {                                                            \
        unsigned long long _val = native_read_tscp(&(aux));     \
@@ -248,8 +213,7 @@ do {                                                            \
 
 #endif /* !CONFIG_PARAVIRT */
 
-
-#define checking_wrmsrl(msr, val) wrmsr_safe((msr), (u32)(val),                \
+#define wrmsrl_safe(msr, val) wrmsr_safe((msr), (u32)(val),            \
                                             (u32)((val) >> 32))
 
 #define write_tsc(val1, val2) wrmsr(MSR_IA32_TSC, (val1), (val2))
index dc580c42851c223a1f21142bbb3a0b8983e18975..c0fa356e90de24ea60ba8a0ac90c39e6bb05d73b 100644 (file)
@@ -44,28 +44,14 @@ struct nmiaction {
        const char              *name;
 };
 
-#define register_nmi_handler(t, fn, fg, n)             \
+#define register_nmi_handler(t, fn, fg, n, init...)    \
 ({                                                     \
-       static struct nmiaction fn##_na = {             \
+       static struct nmiaction init fn##_na = {        \
                .handler = (fn),                        \
                .name = (n),                            \
                .flags = (fg),                          \
        };                                              \
-       __register_nmi_handler((t), &fn##_na);  \
-})
-
-/*
- * For special handlers that register/unregister in the
- * init section only.  This should be considered rare.
- */
-#define register_nmi_handler_initonly(t, fn, fg, n)            \
-({                                                     \
-       static struct nmiaction fn##_na __initdata = {          \
-               .handler = (fn),                        \
-               .name = (n),                            \
-               .flags = (fg),                          \
-       };                                              \
-       __register_nmi_handler((t), &fn##_na);  \
+       __register_nmi_handler((t), &fn##_na);          \
 })
 
 int __register_nmi_handler(unsigned int, struct nmiaction *);
index 6cbbabf52707f9d492a3e3d6687c37b24369cdfb..0b47ddb6f00b300366253a343c4a78424a8fc280 100644 (file)
@@ -128,21 +128,11 @@ static inline u64 paravirt_read_msr(unsigned msr, int *err)
        return PVOP_CALL2(u64, pv_cpu_ops.read_msr, msr, err);
 }
 
-static inline int paravirt_rdmsr_regs(u32 *regs)
-{
-       return PVOP_CALL1(int, pv_cpu_ops.rdmsr_regs, regs);
-}
-
 static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high)
 {
        return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high);
 }
 
-static inline int paravirt_wrmsr_regs(u32 *regs)
-{
-       return PVOP_CALL1(int, pv_cpu_ops.wrmsr_regs, regs);
-}
-
 /* These should all do BUG_ON(_err), but our headers are too tangled. */
 #define rdmsr(msr, val1, val2)                 \
 do {                                           \
@@ -176,9 +166,6 @@ do {                                                \
        _err;                                   \
 })
 
-#define rdmsr_safe_regs(regs)  paravirt_rdmsr_regs(regs)
-#define wrmsr_safe_regs(regs)  paravirt_wrmsr_regs(regs)
-
 static inline int rdmsrl_safe(unsigned msr, unsigned long long *p)
 {
        int err;
@@ -186,32 +173,6 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p)
        *p = paravirt_read_msr(msr, &err);
        return err;
 }
-static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
-{
-       u32 gprs[8] = { 0 };
-       int err;
-
-       gprs[1] = msr;
-       gprs[7] = 0x9c5a203a;
-
-       err = paravirt_rdmsr_regs(gprs);
-
-       *p = gprs[0] | ((u64)gprs[2] << 32);
-
-       return err;
-}
-
-static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
-{
-       u32 gprs[8] = { 0 };
-
-       gprs[0] = (u32)val;
-       gprs[1] = msr;
-       gprs[2] = val >> 32;
-       gprs[7] = 0x9c5a203a;
-
-       return paravirt_wrmsr_regs(gprs);
-}
 
 static inline u64 paravirt_read_tsc(void)
 {
@@ -252,6 +213,8 @@ do {                                                \
        high = _l >> 32;                        \
 } while (0)
 
+#define rdpmcl(counter, val) ((val) = paravirt_read_pmc(counter))
+
 static inline unsigned long long paravirt_rdtscp(unsigned int *aux)
 {
        return PVOP_CALL1(u64, pv_cpu_ops.read_tscp, aux);
index 8e8b9a4987ee0225d0a7e38504436f53f4c81d30..8613cbb7ba41e63d8626e2bae1356793ca279a1d 100644 (file)
@@ -153,9 +153,7 @@ struct pv_cpu_ops {
        /* MSR, PMC and TSR operations.
           err = 0/-EFAULT.  wrmsr returns 0/-EFAULT. */
        u64 (*read_msr)(unsigned int msr, int *err);
-       int (*rdmsr_regs)(u32 *regs);
        int (*write_msr)(unsigned int msr, unsigned low, unsigned high);
-       int (*wrmsr_regs)(u32 *regs);
 
        u64 (*read_tsc)(void);
        u64 (*read_pmc)(int counter);
index b3a531746026105ba70b4d29293696bc02e32779..5ad24a89b19b323eefbf775a92b7287c1cc95c65 100644 (file)
@@ -7,9 +7,13 @@
 #undef DEBUG
 
 #ifdef DEBUG
-#define DBG(x...) printk(x)
+#define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
 #else
-#define DBG(x...)
+#define DBG(fmt, ...)                          \
+do {                                           \
+       if (0)                                  \
+               printk(fmt, ##__VA_ARGS__);     \
+} while (0)
 #endif
 
 #define PCI_PROBE_BIOS         0x0001
index 588f52ea810e78d1440013fd8b8043eff2353fb9..c78f14a0df0029a35cbedcb22594fafa1c9110be 100644 (file)
@@ -5,11 +5,10 @@
  * Performance event hw details:
  */
 
-#define X86_PMC_MAX_GENERIC                                   32
-#define X86_PMC_MAX_FIXED                                      3
+#define INTEL_PMC_MAX_GENERIC                                 32
+#define INTEL_PMC_MAX_FIXED                                    3
+#define INTEL_PMC_IDX_FIXED                                   32
 
-#define X86_PMC_IDX_GENERIC                                    0
-#define X86_PMC_IDX_FIXED                                     32
 #define X86_PMC_IDX_MAX                                               64
 
 #define MSR_ARCH_PERFMON_PERFCTR0                            0xc1
@@ -48,8 +47,7 @@
        (X86_RAW_EVENT_MASK          |  \
         AMD64_EVENTSEL_EVENT)
 #define AMD64_NUM_COUNTERS                             4
-#define AMD64_NUM_COUNTERS_F15H                                6
-#define AMD64_NUM_COUNTERS_MAX                         AMD64_NUM_COUNTERS_F15H
+#define AMD64_NUM_COUNTERS_CORE                                6
 
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL          0x3c
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK                (0x00 << 8)
@@ -121,16 +119,16 @@ struct x86_pmu_capability {
 
 /* Instr_Retired.Any: */
 #define MSR_ARCH_PERFMON_FIXED_CTR0    0x309
-#define X86_PMC_IDX_FIXED_INSTRUCTIONS (X86_PMC_IDX_FIXED + 0)
+#define INTEL_PMC_IDX_FIXED_INSTRUCTIONS       (INTEL_PMC_IDX_FIXED + 0)
 
 /* CPU_CLK_Unhalted.Core: */
 #define MSR_ARCH_PERFMON_FIXED_CTR1    0x30a
-#define X86_PMC_IDX_FIXED_CPU_CYCLES   (X86_PMC_IDX_FIXED + 1)
+#define INTEL_PMC_IDX_FIXED_CPU_CYCLES (INTEL_PMC_IDX_FIXED + 1)
 
 /* CPU_CLK_Unhalted.Ref: */
 #define MSR_ARCH_PERFMON_FIXED_CTR2    0x30b
-#define X86_PMC_IDX_FIXED_REF_CYCLES   (X86_PMC_IDX_FIXED + 2)
-#define X86_PMC_MSK_FIXED_REF_CYCLES   (1ULL << X86_PMC_IDX_FIXED_REF_CYCLES)
+#define INTEL_PMC_IDX_FIXED_REF_CYCLES (INTEL_PMC_IDX_FIXED + 2)
+#define INTEL_PMC_MSK_FIXED_REF_CYCLES (1ULL << INTEL_PMC_IDX_FIXED_REF_CYCLES)
 
 /*
  * We model BTS tracing as another fixed-mode PMC.
@@ -139,7 +137,7 @@ struct x86_pmu_capability {
  * values are used by actual fixed events and higher values are used
  * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
  */
-#define X86_PMC_IDX_FIXED_BTS                          (X86_PMC_IDX_FIXED + 16)
+#define INTEL_PMC_IDX_FIXED_BTS                                (INTEL_PMC_IDX_FIXED + 16)
 
 /*
  * IBS cpuid feature detection
@@ -234,6 +232,7 @@ struct perf_guest_switch_msr {
 
 extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr);
 extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap);
+extern void perf_check_microcode(void);
 #else
 static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
 {
@@ -247,6 +246,7 @@ static inline void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
 }
 
 static inline void perf_events_lapic_init(void)        { }
+static inline void perf_check_microcode(void) { }
 #endif
 
 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
index 98391db840c6d05113768c42be494f4205966741..f2b489cf1602349092d26d6ea68109cca3589c4d 100644 (file)
@@ -2,9 +2,9 @@
 #define _ASM_X86_PGTABLE_2LEVEL_H
 
 #define pte_ERROR(e) \
-       printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low)
+       pr_err("%s:%d: bad pte %08lx\n", __FILE__, __LINE__, (e).pte_low)
 #define pgd_ERROR(e) \
-       printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+       pr_err("%s:%d: bad pgd %08lx\n", __FILE__, __LINE__, pgd_val(e))
 
 /*
  * Certain architectures need to do special things when PTEs
index cb00ccc7d571f2b5245f935bde849c5c5e289635..4cc9f2b7cdc35a854f185b2ab91d49a9fcd1be4f 100644 (file)
@@ -9,13 +9,13 @@
  */
 
 #define pte_ERROR(e)                                                   \
-       printk("%s:%d: bad pte %p(%08lx%08lx).\n",                      \
+       pr_err("%s:%d: bad pte %p(%08lx%08lx)\n",                       \
               __FILE__, __LINE__, &(e), (e).pte_high, (e).pte_low)
 #define pmd_ERROR(e)                                                   \
-       printk("%s:%d: bad pmd %p(%016Lx).\n",                          \
+       pr_err("%s:%d: bad pmd %p(%016Lx)\n",                           \
               __FILE__, __LINE__, &(e), pmd_val(e))
 #define pgd_ERROR(e)                                                   \
-       printk("%s:%d: bad pgd %p(%016Lx).\n",                          \
+       pr_err("%s:%d: bad pgd %p(%016Lx)\n",                           \
               __FILE__, __LINE__, &(e), pgd_val(e))
 
 /* Rules for using set_pte: the pte being assigned *must* be
index 975f709e09ae5cf9e6c3fcf7440cbc4496e036a1..8251be02301ef2be43f0e73d638c0f264aedb936 100644 (file)
@@ -26,16 +26,16 @@ extern pgd_t init_level4_pgt[];
 extern void paging_init(void);
 
 #define pte_ERROR(e)                                   \
-       printk("%s:%d: bad pte %p(%016lx).\n",          \
+       pr_err("%s:%d: bad pte %p(%016lx)\n",           \
               __FILE__, __LINE__, &(e), pte_val(e))
 #define pmd_ERROR(e)                                   \
-       printk("%s:%d: bad pmd %p(%016lx).\n",          \
+       pr_err("%s:%d: bad pmd %p(%016lx)\n",           \
               __FILE__, __LINE__, &(e), pmd_val(e))
 #define pud_ERROR(e)                                   \
-       printk("%s:%d: bad pud %p(%016lx).\n",          \
+       pr_err("%s:%d: bad pud %p(%016lx)\n",           \
               __FILE__, __LINE__, &(e), pud_val(e))
 #define pgd_ERROR(e)                                   \
-       printk("%s:%d: bad pgd %p(%016lx).\n",          \
+       pr_err("%s:%d: bad pgd %p(%016lx)\n",           \
               __FILE__, __LINE__, &(e), pgd_val(e))
 
 struct mm_struct;
index fce3f4ae5bd6d93fc6b2b2f0599600b4914395f8..fe1ec5bcd84644b4c4c0b68660be85dae0bd39ad 100644 (file)
@@ -21,8 +21,9 @@ struct real_mode_header {
        u32     wakeup_header;
 #endif
        /* APM/BIOS reboot */
-#ifdef CONFIG_X86_32
        u32     machine_real_restart_asm;
+#ifdef CONFIG_X86_64
+       u32     machine_real_restart_seg;
 #endif
 };
 
index 92f297069e87c6c6befa12c7ada4fd21b7436365..a82c4f1b4d83e96daf1d99126a290c45ffa38a6c 100644 (file)
@@ -18,8 +18,8 @@ extern struct machine_ops machine_ops;
 
 void native_machine_crash_shutdown(struct pt_regs *regs);
 void native_machine_shutdown(void);
-void machine_real_restart(unsigned int type);
-/* These must match dispatch_table in reboot_32.S */
+void __noreturn machine_real_restart(unsigned int type);
+/* These must match dispatch in arch/x86/realmore/rm/reboot.S */
 #define MRR_BIOS       0
 #define MRR_APM                1
 
index f48394513c377b3d540c6c0ec7da258645d3b06e..2ffa95dc2333bcc5a36efb898fd7ad12e95f5842 100644 (file)
@@ -169,11 +169,6 @@ void x86_idle_thread_init(unsigned int cpu, struct task_struct *idle);
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)   per_cpu(x86_cpu_to_apicid, cpu)
 
-/* We don't mark CPUs online until __cpu_up(), so we need another measure */
-static inline int num_booting_cpus(void)
-{
-       return cpumask_weight(cpu_callout_mask);
-}
 #else /* !CONFIG_SMP */
 #define wbinvd_on_cpu(cpu)     wbinvd()
 static inline int wbinvd_on_all_cpus(void)
index 8e796fbbf9c66e439418dd84580e855a173b4a12..d8def8b3dba0b46a9d52b06d65262560a8c3cca2 100644 (file)
@@ -17,6 +17,8 @@
 
 /* Handles exceptions in both to and from, but doesn't do access_ok */
 __must_check unsigned long
+copy_user_enhanced_fast_string(void *to, const void *from, unsigned len);
+__must_check unsigned long
 copy_user_generic_string(void *to, const void *from, unsigned len);
 __must_check unsigned long
 copy_user_generic_unrolled(void *to, const void *from, unsigned len);
@@ -26,9 +28,16 @@ copy_user_generic(void *to, const void *from, unsigned len)
 {
        unsigned ret;
 
-       alternative_call(copy_user_generic_unrolled,
+       /*
+        * If CPU has ERMS feature, use copy_user_enhanced_fast_string.
+        * Otherwise, if CPU has rep_good feature, use copy_user_generic_string.
+        * Otherwise, use copy_user_generic_unrolled.
+        */
+       alternative_call_2(copy_user_generic_unrolled,
                         copy_user_generic_string,
                         X86_FEATURE_REP_GOOD,
+                        copy_user_enhanced_fast_string,
+                        X86_FEATURE_ERMS,
                         ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from),
                                     "=d" (len)),
                         "1" (to), "2" (from), "3" (len)
index 1e9bed14f7aecd9bfe6bf7ad2df2f8772cd5d5f2..f3971bbcd1de3ee52ddda97b8bd02fbcc815aef1 100644 (file)
@@ -48,7 +48,7 @@ struct arch_uprobe_task {
 #endif
 };
 
-extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm);
+extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
 extern int  arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
 extern int  arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
 extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
index 6149b476d9dffe06bcd1e3e3136bc335fd3dbf98..a06983cdc125d842c58ca13dfc6817282413ee54 100644 (file)
 #define IPI_RESET_LIMIT                        1
 /* after this # consecutive successes, bump up the throttle if it was lowered */
 #define COMPLETE_THRESHOLD             5
+/* after this # of giveups (fall back to kernel IPI's) disable the use of
+   the BAU for a period of time */
+#define GIVEUP_LIMIT                   100
 
 #define UV_LB_SUBNODEID                        0x10
 
 #define FLUSH_RETRY_TIMEOUT            2
 #define FLUSH_GIVEUP                   3
 #define FLUSH_COMPLETE                 4
-#define FLUSH_RETRY_BUSYBUG            5
 
 /*
  * tuning the action when the numalink network is extremely delayed
                                                   microseconds */
 #define CONGESTED_REPS                 10      /* long delays averaged over
                                                   this many broadcasts */
-#define CONGESTED_PERIOD               30      /* time for the bau to be
+#define DISABLED_PERIOD                        10      /* time for the bau to be
                                                   disabled, in seconds */
 /* see msg_type: */
 #define MSG_NOOP                       0
@@ -520,6 +522,12 @@ struct ptc_stats {
        unsigned long   s_uv2_wars;             /* uv2 workaround, perm. busy */
        unsigned long   s_uv2_wars_hw;          /* uv2 workaround, hiwater */
        unsigned long   s_uv2_war_waits;        /* uv2 workaround, long waits */
+       unsigned long   s_overipilimit;         /* over the ipi reset limit */
+       unsigned long   s_giveuplimit;          /* disables, over giveup limit*/
+       unsigned long   s_enters;               /* entries to the driver */
+       unsigned long   s_ipifordisabled;       /* fall back to IPI; disabled */
+       unsigned long   s_plugged;              /* plugged by h/w bug*/
+       unsigned long   s_congested;            /* giveup on long wait */
        /* destination statistics */
        unsigned long   d_alltlb;               /* times all tlb's on this
                                                   cpu were flushed */
@@ -586,8 +594,8 @@ struct bau_control {
        int                     timeout_tries;
        int                     ipi_attempts;
        int                     conseccompletes;
-       int                     baudisabled;
-       int                     set_bau_off;
+       short                   nobau;
+       short                   baudisabled;
        short                   cpu;
        short                   osnode;
        short                   uvhub_cpu;
@@ -596,14 +604,16 @@ struct bau_control {
        short                   cpus_in_socket;
        short                   cpus_in_uvhub;
        short                   partition_base_pnode;
-       short                   using_desc; /* an index, like uvhub_cpu */
-       unsigned int            inuse_map;
+       short                   busy;       /* all were busy (war) */
        unsigned short          message_number;
        unsigned short          uvhub_quiesce;
        short                   socket_acknowledge_count[DEST_Q_SIZE];
        cycles_t                send_message;
+       cycles_t                period_end;
+       cycles_t                period_time;
        spinlock_t              uvhub_lock;
        spinlock_t              queue_lock;
+       spinlock_t              disable_lock;
        /* tunables */
        int                     max_concurr;
        int                     max_concurr_const;
@@ -614,9 +624,9 @@ struct bau_control {
        int                     complete_threshold;
        int                     cong_response_us;
        int                     cong_reps;
-       int                     cong_period;
-       unsigned long           clocks_per_100_usec;
-       cycles_t                period_time;
+       cycles_t                disabled_period;
+       int                     period_giveups;
+       int                     giveup_limit;
        long                    period_requests;
        struct hub_and_pnode    *thp;
 };
index 92e54abf89e0bc31aae93b298ae5d42b7994fef7..f90f0a587c66c34f235ea741596c737789f92cf0 100644 (file)
@@ -9,15 +9,6 @@
 #include <asm/ipi.h>
 #include <linux/cpumask.h>
 
-/*
- * Need to use more than cpu 0, because we need more vectors
- * when MSI-X are used.
- */
-static const struct cpumask *x2apic_target_cpus(void)
-{
-       return cpu_online_mask;
-}
-
 static int x2apic_apic_id_valid(int apicid)
 {
        return 1;
@@ -28,15 +19,6 @@ static int x2apic_apic_id_registered(void)
        return 1;
 }
 
-/*
- * For now each logical cpu is in its own vector allocation domain.
- */
-static void x2apic_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       cpumask_clear(retmask);
-       cpumask_set_cpu(cpu, retmask);
-}
-
 static void
 __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
 {
index c090af10ac7dcc7a6914c915562cc378cd188605..38155f667144ce365f83cd13572d98f78bff5446 100644 (file)
@@ -156,7 +156,6 @@ struct x86_cpuinit_ops {
 /**
  * struct x86_platform_ops - platform specific runtime functions
  * @calibrate_tsc:             calibrate TSC
- * @wallclock_init:            init the wallclock device
  * @get_wallclock:             get time from HW clock like RTC etc.
  * @set_wallclock:             set time back to HW clock
  * @is_untracked_pat_range     exclude from PAT logic
@@ -164,10 +163,10 @@ struct x86_cpuinit_ops {
  * @i8042_detect               pre-detect if i8042 controller exists
  * @save_sched_clock_state:    save state for sched_clock() on suspend
  * @restore_sched_clock_state: restore state for sched_clock() on resume
+ * @apic_post_init:            adjust apic if neeeded
  */
 struct x86_platform_ops {
        unsigned long (*calibrate_tsc)(void);
-       void (*wallclock_init)(void);
        unsigned long (*get_wallclock)(void);
        int (*set_wallclock)(unsigned long nowtime);
        void (*iommu_shutdown)(void);
@@ -177,6 +176,7 @@ struct x86_platform_ops {
        int (*i8042_detect)(void);
        void (*save_sched_clock_state)(void);
        void (*restore_sched_clock_state)(void);
+       void (*apic_post_init)(void);
 };
 
 struct pci_dev;
index 1f84794f0759327c387d602cddccb3d479188f92..931280ff8299471df09b60033cdb06b46a361677 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) "SMP alternatives: " fmt
+
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/mutex.h>
@@ -63,8 +65,11 @@ static int __init setup_noreplace_paravirt(char *str)
 __setup("noreplace-paravirt", setup_noreplace_paravirt);
 #endif
 
-#define DPRINTK(fmt, args...) if (debug_alternative) \
-       printk(KERN_DEBUG fmt, args)
+#define DPRINTK(fmt, ...)                              \
+do {                                                   \
+       if (debug_alternative)                          \
+               printk(KERN_DEBUG fmt, ##__VA_ARGS__);  \
+} while (0)
 
 /*
  * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes
@@ -428,7 +433,7 @@ void alternatives_smp_switch(int smp)
         * If this still occurs then you should see a hang
         * or crash shortly after this line:
         */
-       printk("lockdep: fixing up alternatives.\n");
+       pr_info("lockdep: fixing up alternatives\n");
 #endif
 
        if (noreplace_smp || smp_alt_once || skip_smp_alternatives)
@@ -444,14 +449,14 @@ void alternatives_smp_switch(int smp)
        if (smp == smp_mode) {
                /* nothing */
        } else if (smp) {
-               printk(KERN_INFO "SMP alternatives: switching to SMP code\n");
+               pr_info("switching to SMP code\n");
                clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
                clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
                list_for_each_entry(mod, &smp_alt_modules, next)
                        alternatives_smp_lock(mod->locks, mod->locks_end,
                                              mod->text, mod->text_end);
        } else {
-               printk(KERN_INFO "SMP alternatives: switching to UP code\n");
+               pr_info("switching to UP code\n");
                set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
                set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
                list_for_each_entry(mod, &smp_alt_modules, next)
@@ -546,7 +551,7 @@ void __init alternative_instructions(void)
 #ifdef CONFIG_SMP
        if (smp_alt_once) {
                if (1 == num_possible_cpus()) {
-                       printk(KERN_INFO "SMP alternatives: switching to UP code\n");
+                       pr_info("switching to UP code\n");
                        set_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
                        set_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
 
@@ -664,7 +669,7 @@ static int __kprobes stop_machine_text_poke(void *data)
        struct text_poke_param *p;
        int i;
 
-       if (atomic_dec_and_test(&stop_machine_first)) {
+       if (atomic_xchg(&stop_machine_first, 0)) {
                for (i = 0; i < tpp->nparams; i++) {
                        p = &tpp->params[i];
                        text_poke(p->addr, p->opcode, p->len);
index be16854591cc26a2b0349b6f7d9e0cc446340e32..aadf3359e2a77660b5ee68ac549b5a82fcad8695 100644 (file)
@@ -2,6 +2,9 @@
  * Shared support code for AMD K8 northbridges and derivates.
  * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/init.h>
@@ -16,6 +19,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
        {}
 };
 EXPORT_SYMBOL(amd_nb_misc_ids);
@@ -258,7 +262,7 @@ void amd_flush_garts(void)
        }
        spin_unlock_irqrestore(&gart_lock, flags);
        if (!flushed)
-               printk("nothing to flush?\n");
+               pr_notice("nothing to flush?\n");
 }
 EXPORT_SYMBOL_GPL(amd_flush_garts);
 
@@ -269,11 +273,10 @@ static __init int init_amd_nbs(void)
        err = amd_cache_northbridges();
 
        if (err < 0)
-               printk(KERN_NOTICE "AMD NB: Cannot enumerate AMD northbridges.\n");
+               pr_notice("Cannot enumerate AMD northbridges\n");
 
        if (amd_cache_gart() < 0)
-               printk(KERN_NOTICE "AMD NB: Cannot initialize GART flush words, "
-                      "GART support disabled.\n");
+               pr_notice("Cannot initialize GART flush words, GART support disabled\n");
 
        return err;
 }
index 39a222e094af0b1ac3c0904a9c977be9b2a95795..c421512ca5eb33ceb79de6ce3b4284a96356ede4 100644 (file)
@@ -2123,6 +2123,25 @@ void default_init_apic_ldr(void)
        apic_write(APIC_LDR, val);
 }
 
+int default_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
+                                  const struct cpumask *andmask,
+                                  unsigned int *apicid)
+{
+       unsigned int cpu;
+
+       for_each_cpu_and(cpu, cpumask, andmask) {
+               if (cpumask_test_cpu(cpu, cpu_online_mask))
+                       break;
+       }
+
+       if (likely(cpu < nr_cpu_ids)) {
+               *apicid = per_cpu(x86_cpu_to_apicid, cpu);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
 /*
  * Power management
  */
index 0e881c46e8c856ed41f6fc095e0381853b7e781b..00c77cf78e9e1839973923076053fdf92d75a54e 100644 (file)
@@ -36,25 +36,6 @@ static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        return 1;
 }
 
-static const struct cpumask *flat_target_cpus(void)
-{
-       return cpu_online_mask;
-}
-
-static void flat_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       /* Careful. Some cpus do not strictly honor the set of cpus
-        * specified in the interrupt destination when using lowest
-        * priority interrupt delivery mode.
-        *
-        * In particular there was a hyperthreading cpu observed to
-        * deliver interrupts to the wrong hyperthread when only one
-        * hyperthread was specified in the interrupt desitination.
-        */
-       cpumask_clear(retmask);
-       cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 /*
  * Set up the logical destination ID.
  *
@@ -92,7 +73,7 @@ static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
 }
 
 static void
- flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
+flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
 {
        unsigned long mask = cpumask_bits(cpumask)[0];
        int cpu = smp_processor_id();
@@ -186,7 +167,7 @@ static struct apic apic_flat =  {
        .irq_delivery_mode              = dest_LowestPrio,
        .irq_dest_mode                  = 1, /* logical */
 
-       .target_cpus                    = flat_target_cpus,
+       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = NULL,
@@ -210,8 +191,7 @@ static struct apic apic_flat =  {
        .set_apic_id                    = set_apic_id,
        .apic_id_mask                   = 0xFFu << 24,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = flat_send_IPI_mask,
        .send_IPI_mask_allbutself       = flat_send_IPI_mask_allbutself,
@@ -262,17 +242,6 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        return 0;
 }
 
-static const struct cpumask *physflat_target_cpus(void)
-{
-       return cpu_online_mask;
-}
-
-static void physflat_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       cpumask_clear(retmask);
-       cpumask_set_cpu(cpu, retmask);
-}
-
 static void physflat_send_IPI_mask(const struct cpumask *cpumask, int vector)
 {
        default_send_IPI_mask_sequence_phys(cpumask, vector);
@@ -294,38 +263,6 @@ static void physflat_send_IPI_all(int vector)
        physflat_send_IPI_mask(cpu_online_mask, vector);
 }
 
-static unsigned int physflat_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-       int cpu;
-
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       cpu = cpumask_first(cpumask);
-       if ((unsigned)cpu < nr_cpu_ids)
-               return per_cpu(x86_cpu_to_apicid, cpu);
-       else
-               return BAD_APICID;
-}
-
-static unsigned int
-physflat_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                               const struct cpumask *andmask)
-{
-       int cpu;
-
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       for_each_cpu_and(cpu, cpumask, andmask) {
-               if (cpumask_test_cpu(cpu, cpu_online_mask))
-                       break;
-       }
-       return per_cpu(x86_cpu_to_apicid, cpu);
-}
-
 static int physflat_probe(void)
 {
        if (apic == &apic_physflat || num_possible_cpus() > 8)
@@ -345,13 +282,13 @@ static struct apic apic_physflat =  {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = physflat_target_cpus,
+       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = 0,
        .check_apicid_used              = NULL,
        .check_apicid_present           = NULL,
 
-       .vector_allocation_domain       = physflat_vector_allocation_domain,
+       .vector_allocation_domain       = default_vector_allocation_domain,
        /* not needed, but shouldn't hurt: */
        .init_apic_ldr                  = flat_init_apic_ldr,
 
@@ -370,8 +307,7 @@ static struct apic apic_physflat =  {
        .set_apic_id                    = set_apic_id,
        .apic_id_mask                   = 0xFFu << 24,
 
-       .cpu_mask_to_apicid             = physflat_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = physflat_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = physflat_send_IPI_mask,
        .send_IPI_mask_allbutself       = physflat_send_IPI_mask_allbutself,
index a6e4c6e06c08feaca0752c76619ec8c482a5a77d..e145f28b40993d4753d714f9247a46a8507fa959 100644 (file)
@@ -100,12 +100,12 @@ static unsigned long noop_check_apicid_present(int bit)
        return physid_isset(bit, phys_cpu_present_map);
 }
 
-static void noop_vector_allocation_domain(int cpu, struct cpumask *retmask)
+static void noop_vector_allocation_domain(int cpu, struct cpumask *retmask,
+                                         const struct cpumask *mask)
 {
        if (cpu != 0)
                pr_warning("APIC: Vector allocated for non-BSP cpu\n");
-       cpumask_clear(retmask);
-       cpumask_set_cpu(cpu, retmask);
+       cpumask_copy(retmask, cpumask_of(cpu));
 }
 
 static u32 noop_apic_read(u32 reg)
@@ -159,8 +159,7 @@ struct apic apic_noop = {
        .set_apic_id                    = NULL,
        .apic_id_mask                   = 0x0F << 24,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = noop_send_IPI_mask,
        .send_IPI_mask_allbutself       = noop_send_IPI_mask_allbutself,
index 6ec6d5d297c3a7f01dca9e6c64cd11f44e1a295e..bc552cff257834bee7a8c1078112ea46380892d4 100644 (file)
@@ -72,17 +72,6 @@ static int numachip_phys_pkg_id(int initial_apic_id, int index_msb)
        return initial_apic_id >> index_msb;
 }
 
-static const struct cpumask *numachip_target_cpus(void)
-{
-       return cpu_online_mask;
-}
-
-static void numachip_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       cpumask_clear(retmask);
-       cpumask_set_cpu(cpu, retmask);
-}
-
 static int __cpuinit numachip_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 {
        union numachip_csr_g3_ext_irq_gen int_gen;
@@ -157,38 +146,6 @@ static void numachip_send_IPI_self(int vector)
        __default_send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
 }
 
-static unsigned int numachip_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-       int cpu;
-
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       cpu = cpumask_first(cpumask);
-       if (likely((unsigned)cpu < nr_cpu_ids))
-               return per_cpu(x86_cpu_to_apicid, cpu);
-
-       return BAD_APICID;
-}
-
-static unsigned int
-numachip_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                               const struct cpumask *andmask)
-{
-       int cpu;
-
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       for_each_cpu_and(cpu, cpumask, andmask) {
-               if (cpumask_test_cpu(cpu, cpu_online_mask))
-                       break;
-       }
-       return per_cpu(x86_cpu_to_apicid, cpu);
-}
-
 static int __init numachip_probe(void)
 {
        return apic == &apic_numachip;
@@ -253,13 +210,13 @@ static struct apic apic_numachip __refconst = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = numachip_target_cpus,
+       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = 0,
        .check_apicid_used              = NULL,
        .check_apicid_present           = NULL,
 
-       .vector_allocation_domain       = numachip_vector_allocation_domain,
+       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = flat_init_apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -277,8 +234,7 @@ static struct apic apic_numachip __refconst = {
        .set_apic_id                    = set_apic_id,
        .apic_id_mask                   = 0xffU << 24,
 
-       .cpu_mask_to_apicid             = numachip_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = numachip_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = numachip_send_IPI_mask,
        .send_IPI_mask_allbutself       = numachip_send_IPI_mask_allbutself,
index 31fbdbfbf9607982c8769b58804b32b2c6ac29f5..d50e3640d5aed53daf4110ef68193cf0cbdac826 100644 (file)
@@ -26,15 +26,6 @@ static int bigsmp_apic_id_registered(void)
        return 1;
 }
 
-static const struct cpumask *bigsmp_target_cpus(void)
-{
-#ifdef CONFIG_SMP
-       return cpu_online_mask;
-#else
-       return cpumask_of(0);
-#endif
-}
-
 static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
 {
        return 0;
@@ -105,32 +96,6 @@ static int bigsmp_check_phys_apicid_present(int phys_apicid)
        return 1;
 }
 
-/* As we are using single CPU as destination, pick only one CPU here */
-static unsigned int bigsmp_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-       int cpu = cpumask_first(cpumask);
-
-       if (cpu < nr_cpu_ids)
-               return cpu_physical_id(cpu);
-       return BAD_APICID;
-}
-
-static unsigned int bigsmp_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                             const struct cpumask *andmask)
-{
-       int cpu;
-
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       for_each_cpu_and(cpu, cpumask, andmask) {
-               if (cpumask_test_cpu(cpu, cpu_online_mask))
-                       return cpu_physical_id(cpu);
-       }
-       return BAD_APICID;
-}
-
 static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
 {
        return cpuid_apic >> index_msb;
@@ -177,12 +142,6 @@ static const struct dmi_system_id bigsmp_dmi_table[] = {
        { } /* NULL entry stops DMI scanning */
 };
 
-static void bigsmp_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       cpumask_clear(retmask);
-       cpumask_set_cpu(cpu, retmask);
-}
-
 static int probe_bigsmp(void)
 {
        if (def_to_bigsmp)
@@ -205,13 +164,13 @@ static struct apic apic_bigsmp = {
        /* phys delivery to target CPU: */
        .irq_dest_mode                  = 0,
 
-       .target_cpus                    = bigsmp_target_cpus,
+       .target_cpus                    = default_target_cpus,
        .disable_esr                    = 1,
        .dest_logical                   = 0,
        .check_apicid_used              = bigsmp_check_apicid_used,
        .check_apicid_present           = bigsmp_check_apicid_present,
 
-       .vector_allocation_domain       = bigsmp_vector_allocation_domain,
+       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = bigsmp_init_apic_ldr,
 
        .ioapic_phys_id_map             = bigsmp_ioapic_phys_id_map,
@@ -229,8 +188,7 @@ static struct apic apic_bigsmp = {
        .set_apic_id                    = NULL,
        .apic_id_mask                   = 0xFF << 24,
 
-       .cpu_mask_to_apicid             = bigsmp_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = bigsmp_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = bigsmp_send_IPI_mask,
        .send_IPI_mask_allbutself       = NULL,
index db4ab1be3c79470045fc9ebe44a11315b2416309..0874799a98c6fbe37ee34baaad7cbdc3bd616744 100644 (file)
@@ -394,21 +394,6 @@ static void es7000_enable_apic_mode(void)
                WARN(1, "Command failed, status = %x\n", mip_status);
 }
 
-static void es7000_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       /* Careful. Some cpus do not strictly honor the set of cpus
-        * specified in the interrupt destination when using lowest
-        * priority interrupt delivery mode.
-        *
-        * In particular there was a hyperthreading cpu observed to
-        * deliver interrupts to the wrong hyperthread when only one
-        * hyperthread was specified in the interrupt desitination.
-        */
-       cpumask_clear(retmask);
-       cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
-
 static void es7000_wait_for_init_deassert(atomic_t *deassert)
 {
        while (!atomic_read(deassert))
@@ -540,45 +525,49 @@ static int es7000_check_phys_apicid_present(int cpu_physical_apicid)
        return 1;
 }
 
-static unsigned int es7000_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static inline int
+es7000_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
 {
        unsigned int round = 0;
-       int cpu, uninitialized_var(apicid);
+       unsigned int cpu, uninitialized_var(apicid);
 
        /*
         * The cpus in the mask must all be on the apic cluster.
         */
-       for_each_cpu(cpu, cpumask) {
+       for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
                int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
 
                if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
                        WARN(1, "Not a valid mask!");
 
-                       return BAD_APICID;
+                       return -EINVAL;
                }
-               apicid = new_apicid;
+               apicid |= new_apicid;
                round++;
        }
-       return apicid;
+       if (!round)
+               return -EINVAL;
+       *dest_id = apicid;
+       return 0;
 }
 
-static unsigned int
+static int
 es7000_cpu_mask_to_apicid_and(const struct cpumask *inmask,
-                             const struct cpumask *andmask)
+                             const struct cpumask *andmask,
+                             unsigned int *apicid)
 {
-       int apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
        cpumask_var_t cpumask;
+       *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
 
        if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
-               return apicid;
+               return 0;
 
        cpumask_and(cpumask, inmask, andmask);
-       cpumask_and(cpumask, cpumask, cpu_online_mask);
-       apicid = es7000_cpu_mask_to_apicid(cpumask);
+       es7000_cpu_mask_to_apicid(cpumask, apicid);
 
        free_cpumask_var(cpumask);
 
-       return apicid;
+       return 0;
 }
 
 static int es7000_phys_pkg_id(int cpuid_apic, int index_msb)
@@ -638,7 +627,7 @@ static struct apic __refdata apic_es7000_cluster = {
        .check_apicid_used              = es7000_check_apicid_used,
        .check_apicid_present           = es7000_check_apicid_present,
 
-       .vector_allocation_domain       = es7000_vector_allocation_domain,
+       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = es7000_init_apic_ldr_cluster,
 
        .ioapic_phys_id_map             = es7000_ioapic_phys_id_map,
@@ -656,7 +645,6 @@ static struct apic __refdata apic_es7000_cluster = {
        .set_apic_id                    = NULL,
        .apic_id_mask                   = 0xFF << 24,
 
-       .cpu_mask_to_apicid             = es7000_cpu_mask_to_apicid,
        .cpu_mask_to_apicid_and         = es7000_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = es7000_send_IPI_mask,
@@ -705,7 +693,7 @@ static struct apic __refdata apic_es7000 = {
        .check_apicid_used              = es7000_check_apicid_used,
        .check_apicid_present           = es7000_check_apicid_present,
 
-       .vector_allocation_domain       = es7000_vector_allocation_domain,
+       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = es7000_init_apic_ldr,
 
        .ioapic_phys_id_map             = es7000_ioapic_phys_id_map,
@@ -723,7 +711,6 @@ static struct apic __refdata apic_es7000 = {
        .set_apic_id                    = NULL,
        .apic_id_mask                   = 0xFF << 24,
 
-       .cpu_mask_to_apicid             = es7000_cpu_mask_to_apicid,
        .cpu_mask_to_apicid_and         = es7000_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = es7000_send_IPI_mask,
index 5f0ff597437c17add5334629458f8c2b35ffa148..406eee7846849990d8f87d53243e6cd171944e17 100644 (file)
@@ -448,8 +448,8 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi
 
        entry = alloc_irq_pin_list(node);
        if (!entry) {
-               printk(KERN_ERR "can not alloc irq_pin_list (%d,%d,%d)\n",
-                               node, apic, pin);
+               pr_err("can not alloc irq_pin_list (%d,%d,%d)\n",
+                      node, apic, pin);
                return -ENOMEM;
        }
        entry->apic = apic;
@@ -661,7 +661,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
        ioapic_mask_entry(apic, pin);
        entry = ioapic_read_entry(apic, pin);
        if (entry.irr)
-               printk(KERN_ERR "Unable to reset IRR for apic: %d, pin :%d\n",
+               pr_err("Unable to reset IRR for apic: %d, pin :%d\n",
                       mpc_ioapic_id(apic), pin);
 }
 
@@ -895,7 +895,7 @@ static int irq_polarity(int idx)
                }
                case 2: /* reserved */
                {
-                       printk(KERN_WARNING "broken BIOS!!\n");
+                       pr_warn("broken BIOS!!\n");
                        polarity = 1;
                        break;
                }
@@ -906,7 +906,7 @@ static int irq_polarity(int idx)
                }
                default: /* invalid */
                {
-                       printk(KERN_WARNING "broken BIOS!!\n");
+                       pr_warn("broken BIOS!!\n");
                        polarity = 1;
                        break;
                }
@@ -948,7 +948,7 @@ static int irq_trigger(int idx)
                                }
                                default:
                                {
-                                       printk(KERN_WARNING "broken BIOS!!\n");
+                                       pr_warn("broken BIOS!!\n");
                                        trigger = 1;
                                        break;
                                }
@@ -962,7 +962,7 @@ static int irq_trigger(int idx)
                }
                case 2: /* reserved */
                {
-                       printk(KERN_WARNING "broken BIOS!!\n");
+                       pr_warn("broken BIOS!!\n");
                        trigger = 1;
                        break;
                }
@@ -973,7 +973,7 @@ static int irq_trigger(int idx)
                }
                default: /* invalid */
                {
-                       printk(KERN_WARNING "broken BIOS!!\n");
+                       pr_warn("broken BIOS!!\n");
                        trigger = 0;
                        break;
                }
@@ -991,7 +991,7 @@ static int pin_2_irq(int idx, int apic, int pin)
         * Debugging check, we are in big trouble if this message pops up!
         */
        if (mp_irqs[idx].dstirq != pin)
-               printk(KERN_ERR "broken BIOS or MPTABLE parser, ayiee!!\n");
+               pr_err("broken BIOS or MPTABLE parser, ayiee!!\n");
 
        if (test_bit(bus, mp_bus_not_pci)) {
                irq = mp_irqs[idx].srcbusirq;
@@ -1112,8 +1112,7 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
        static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
-       static int current_offset = VECTOR_OFFSET_START % 8;
-       unsigned int old_vector;
+       static int current_offset = VECTOR_OFFSET_START % 16;
        int cpu, err;
        cpumask_var_t tmp_mask;
 
@@ -1123,35 +1122,45 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
        if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
                return -ENOMEM;
 
-       old_vector = cfg->vector;
-       if (old_vector) {
-               cpumask_and(tmp_mask, mask, cpu_online_mask);
-               cpumask_and(tmp_mask, cfg->domain, tmp_mask);
-               if (!cpumask_empty(tmp_mask)) {
-                       free_cpumask_var(tmp_mask);
-                       return 0;
-               }
-       }
-
        /* Only try and allocate irqs on cpus that are present */
        err = -ENOSPC;
-       for_each_cpu_and(cpu, mask, cpu_online_mask) {
-               int new_cpu;
-               int vector, offset;
+       cpumask_clear(cfg->old_domain);
+       cpu = cpumask_first_and(mask, cpu_online_mask);
+       while (cpu < nr_cpu_ids) {
+               int new_cpu, vector, offset;
 
-               apic->vector_allocation_domain(cpu, tmp_mask);
+               apic->vector_allocation_domain(cpu, tmp_mask, mask);
+
+               if (cpumask_subset(tmp_mask, cfg->domain)) {
+                       err = 0;
+                       if (cpumask_equal(tmp_mask, cfg->domain))
+                               break;
+                       /*
+                        * New cpumask using the vector is a proper subset of
+                        * the current in use mask. So cleanup the vector
+                        * allocation for the members that are not used anymore.
+                        */
+                       cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask);
+                       cfg->move_in_progress = 1;
+                       cpumask_and(cfg->domain, cfg->domain, tmp_mask);
+                       break;
+               }
 
                vector = current_vector;
                offset = current_offset;
 next:
-               vector += 8;
+               vector += 16;
                if (vector >= first_system_vector) {
-                       /* If out of vectors on large boxen, must share them. */
-                       offset = (offset + 1) % 8;
+                       offset = (offset + 1) % 16;
                        vector = FIRST_EXTERNAL_VECTOR + offset;
                }
-               if (unlikely(current_vector == vector))
+
+               if (unlikely(current_vector == vector)) {
+                       cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
+                       cpumask_andnot(tmp_mask, mask, cfg->old_domain);
+                       cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
                        continue;
+               }
 
                if (test_bit(vector, used_vectors))
                        goto next;
@@ -1162,7 +1171,7 @@ next:
                /* Found one! */
                current_vector = vector;
                current_offset = offset;
-               if (old_vector) {
+               if (cfg->vector) {
                        cfg->move_in_progress = 1;
                        cpumask_copy(cfg->old_domain, cfg->domain);
                }
@@ -1346,18 +1355,18 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
 
        if (!IO_APIC_IRQ(irq))
                return;
-       /*
-        * For legacy irqs, cfg->domain starts with cpu 0 for legacy
-        * controllers like 8259. Now that IO-APIC can handle this irq, update
-        * the cfg->domain.
-        */
-       if (irq < legacy_pic->nr_legacy_irqs && cpumask_test_cpu(0, cfg->domain))
-               apic->vector_allocation_domain(0, cfg->domain);
 
        if (assign_irq_vector(irq, cfg, apic->target_cpus()))
                return;
 
-       dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
+       if (apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus(),
+                                        &dest)) {
+               pr_warn("Failed to obtain apicid for ioapic %d, pin %d\n",
+                       mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
+               __clear_irq_vector(irq, cfg);
+
+               return;
+       }
 
        apic_printk(APIC_VERBOSE,KERN_DEBUG
                    "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
@@ -1366,7 +1375,7 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
                    cfg->vector, irq, attr->trigger, attr->polarity, dest);
 
        if (setup_ioapic_entry(irq, &entry, dest, cfg->vector, attr)) {
-               pr_warn("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
+               pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
                        mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
                __clear_irq_vector(irq, cfg);
 
@@ -1469,9 +1478,10 @@ void setup_IO_APIC_irq_extra(u32 gsi)
  * Set up the timer pin, possibly with the 8259A-master behind.
  */
 static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
-                                        unsigned int pin, int vector)
+                                       unsigned int pin, int vector)
 {
        struct IO_APIC_route_entry entry;
+       unsigned int dest;
 
        if (irq_remapping_enabled)
                return;
@@ -1482,9 +1492,13 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
         * We use logical delivery to get the timer IRQ
         * to the first CPU.
         */
+       if (unlikely(apic->cpu_mask_to_apicid_and(apic->target_cpus(),
+                                                 apic->target_cpus(), &dest)))
+               dest = BAD_APICID;
+
        entry.dest_mode = apic->irq_dest_mode;
        entry.mask = 0;                 /* don't mask IRQ for edge */
-       entry.dest = apic->cpu_mask_to_apicid(apic->target_cpus());
+       entry.dest = dest;
        entry.delivery_mode = apic->irq_delivery_mode;
        entry.polarity = 0;
        entry.trigger = 0;
@@ -1521,7 +1535,6 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
                reg_03.raw = io_apic_read(ioapic_idx, 3);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
-       printk("\n");
        printk(KERN_DEBUG "IO APIC #%d......\n", mpc_ioapic_id(ioapic_idx));
        printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
        printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.bits.ID);
@@ -1578,7 +1591,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
                                i,
                                ir_entry->index
                        );
-                       printk("%1d   %1d    %1d    %1d   %1d   "
+                       pr_cont("%1d   %1d    %1d    %1d   %1d   "
                                "%1d    %1d     %X    %02X\n",
                                ir_entry->format,
                                ir_entry->mask,
@@ -1598,7 +1611,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
                                i,
                                entry.dest
                        );
-                       printk("%1d    %1d    %1d   %1d   %1d    "
+                       pr_cont("%1d    %1d    %1d   %1d   %1d    "
                                "%1d    %1d    %02X\n",
                                entry.mask,
                                entry.trigger,
@@ -1651,8 +1664,8 @@ __apicdebuginit(void) print_IO_APICs(void)
                        continue;
                printk(KERN_DEBUG "IRQ%d ", irq);
                for_each_irq_pin(entry, cfg->irq_2_pin)
-                       printk("-> %d:%d", entry->apic, entry->pin);
-               printk("\n");
+                       pr_cont("-> %d:%d", entry->apic, entry->pin);
+               pr_cont("\n");
        }
 
        printk(KERN_INFO ".................................... done.\n");
@@ -1665,9 +1678,9 @@ __apicdebuginit(void) print_APIC_field(int base)
        printk(KERN_DEBUG);
 
        for (i = 0; i < 8; i++)
-               printk(KERN_CONT "%08x", apic_read(base + i*0x10));
+               pr_cont("%08x", apic_read(base + i*0x10));
 
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 }
 
 __apicdebuginit(void) print_local_APIC(void *dummy)
@@ -1769,7 +1782,7 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
                        printk(KERN_DEBUG "... APIC EILVT%d: %08x\n", i, v);
                }
        }
-       printk("\n");
+       pr_cont("\n");
 }
 
 __apicdebuginit(void) print_local_APICs(int maxcpu)
@@ -2065,7 +2078,7 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
                reg_00.raw = io_apic_read(ioapic_idx, 0);
                raw_spin_unlock_irqrestore(&ioapic_lock, flags);
                if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx))
-                       printk("could not set ID!\n");
+                       pr_cont("could not set ID!\n");
                else
                        apic_printk(APIC_VERBOSE, " ok.\n");
        }
@@ -2210,71 +2223,6 @@ void send_cleanup_vector(struct irq_cfg *cfg)
        cfg->move_in_progress = 0;
 }
 
-static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
-{
-       int apic, pin;
-       struct irq_pin_list *entry;
-       u8 vector = cfg->vector;
-
-       for_each_irq_pin(entry, cfg->irq_2_pin) {
-               unsigned int reg;
-
-               apic = entry->apic;
-               pin = entry->pin;
-               /*
-                * With interrupt-remapping, destination information comes
-                * from interrupt-remapping table entry.
-                */
-               if (!irq_remapped(cfg))
-                       io_apic_write(apic, 0x11 + pin*2, dest);
-               reg = io_apic_read(apic, 0x10 + pin*2);
-               reg &= ~IO_APIC_REDIR_VECTOR_MASK;
-               reg |= vector;
-               io_apic_modify(apic, 0x10 + pin*2, reg);
-       }
-}
-
-/*
- * Either sets data->affinity to a valid value, and returns
- * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
- * leaves data->affinity untouched.
- */
-int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
-                         unsigned int *dest_id)
-{
-       struct irq_cfg *cfg = data->chip_data;
-
-       if (!cpumask_intersects(mask, cpu_online_mask))
-               return -1;
-
-       if (assign_irq_vector(data->irq, data->chip_data, mask))
-               return -1;
-
-       cpumask_copy(data->affinity, mask);
-
-       *dest_id = apic->cpu_mask_to_apicid_and(mask, cfg->domain);
-       return 0;
-}
-
-static int
-ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
-                   bool force)
-{
-       unsigned int dest, irq = data->irq;
-       unsigned long flags;
-       int ret;
-
-       raw_spin_lock_irqsave(&ioapic_lock, flags);
-       ret = __ioapic_set_affinity(data, mask, &dest);
-       if (!ret) {
-               /* Only the high 8 bits are valid. */
-               dest = SET_APIC_LOGICAL_ID(dest);
-               __target_IO_APIC_irq(irq, dest, data->chip_data);
-       }
-       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-       return ret;
-}
-
 asmlinkage void smp_irq_move_cleanup_interrupt(void)
 {
        unsigned vector, me;
@@ -2362,6 +2310,87 @@ void irq_force_complete_move(int irq)
 static inline void irq_complete_move(struct irq_cfg *cfg) { }
 #endif
 
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
+{
+       int apic, pin;
+       struct irq_pin_list *entry;
+       u8 vector = cfg->vector;
+
+       for_each_irq_pin(entry, cfg->irq_2_pin) {
+               unsigned int reg;
+
+               apic = entry->apic;
+               pin = entry->pin;
+               /*
+                * With interrupt-remapping, destination information comes
+                * from interrupt-remapping table entry.
+                */
+               if (!irq_remapped(cfg))
+                       io_apic_write(apic, 0x11 + pin*2, dest);
+               reg = io_apic_read(apic, 0x10 + pin*2);
+               reg &= ~IO_APIC_REDIR_VECTOR_MASK;
+               reg |= vector;
+               io_apic_modify(apic, 0x10 + pin*2, reg);
+       }
+}
+
+/*
+ * Either sets data->affinity to a valid value, and returns
+ * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
+ * leaves data->affinity untouched.
+ */
+int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                         unsigned int *dest_id)
+{
+       struct irq_cfg *cfg = data->chip_data;
+       unsigned int irq = data->irq;
+       int err;
+
+       if (!config_enabled(CONFIG_SMP))
+               return -1;
+
+       if (!cpumask_intersects(mask, cpu_online_mask))
+               return -EINVAL;
+
+       err = assign_irq_vector(irq, cfg, mask);
+       if (err)
+               return err;
+
+       err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id);
+       if (err) {
+               if (assign_irq_vector(irq, cfg, data->affinity))
+                       pr_err("Failed to recover vector for irq %d\n", irq);
+               return err;
+       }
+
+       cpumask_copy(data->affinity, mask);
+
+       return 0;
+}
+
+static int
+ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                   bool force)
+{
+       unsigned int dest, irq = data->irq;
+       unsigned long flags;
+       int ret;
+
+       if (!config_enabled(CONFIG_SMP))
+               return -1;
+
+       raw_spin_lock_irqsave(&ioapic_lock, flags);
+       ret = __ioapic_set_affinity(data, mask, &dest);
+       if (!ret) {
+               /* Only the high 8 bits are valid. */
+               dest = SET_APIC_LOGICAL_ID(dest);
+               __target_IO_APIC_irq(irq, dest, data->chip_data);
+               ret = IRQ_SET_MASK_OK_NOCOPY;
+       }
+       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+       return ret;
+}
+
 static void ack_apic_edge(struct irq_data *data)
 {
        irq_complete_move(data->chip_data);
@@ -2541,9 +2570,7 @@ static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
        chip->irq_ack = ir_ack_apic_edge;
        chip->irq_eoi = ir_ack_apic_level;
 
-#ifdef CONFIG_SMP
        chip->irq_set_affinity = set_remapped_irq_affinity;
-#endif
 }
 #endif /* CONFIG_IRQ_REMAP */
 
@@ -2554,9 +2581,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
        .irq_unmask             = unmask_ioapic_irq,
        .irq_ack                = ack_apic_edge,
        .irq_eoi                = ack_apic_level,
-#ifdef CONFIG_SMP
        .irq_set_affinity       = ioapic_set_affinity,
-#endif
        .irq_retrigger          = ioapic_retrigger_irq,
 };
 
@@ -3038,7 +3063,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
        if (err)
                return err;
 
-       dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
+       err = apic->cpu_mask_to_apicid_and(cfg->domain,
+                                          apic->target_cpus(), &dest);
+       if (err)
+               return err;
 
        if (irq_remapped(cfg)) {
                compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id);
@@ -3072,7 +3100,6 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
        return err;
 }
 
-#ifdef CONFIG_SMP
 static int
 msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 {
@@ -3092,9 +3119,8 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 
        __write_msi_msg(data->msi_desc, &msg);
 
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
-#endif /* CONFIG_SMP */
 
 /*
  * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
@@ -3105,9 +3131,7 @@ static struct irq_chip msi_chip = {
        .irq_unmask             = unmask_msi_irq,
        .irq_mask               = mask_msi_irq,
        .irq_ack                = ack_apic_edge,
-#ifdef CONFIG_SMP
        .irq_set_affinity       = msi_set_affinity,
-#endif
        .irq_retrigger          = ioapic_retrigger_irq,
 };
 
@@ -3192,7 +3216,6 @@ void native_teardown_msi_irq(unsigned int irq)
 }
 
 #ifdef CONFIG_DMAR_TABLE
-#ifdef CONFIG_SMP
 static int
 dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
                      bool force)
@@ -3214,19 +3237,15 @@ dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
 
        dmar_msi_write(irq, &msg);
 
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 
-#endif /* CONFIG_SMP */
-
 static struct irq_chip dmar_msi_type = {
        .name                   = "DMAR_MSI",
        .irq_unmask             = dmar_msi_unmask,
        .irq_mask               = dmar_msi_mask,
        .irq_ack                = ack_apic_edge,
-#ifdef CONFIG_SMP
        .irq_set_affinity       = dmar_msi_set_affinity,
-#endif
        .irq_retrigger          = ioapic_retrigger_irq,
 };
 
@@ -3247,7 +3266,6 @@ int arch_setup_dmar_msi(unsigned int irq)
 
 #ifdef CONFIG_HPET_TIMER
 
-#ifdef CONFIG_SMP
 static int hpet_msi_set_affinity(struct irq_data *data,
                                 const struct cpumask *mask, bool force)
 {
@@ -3267,19 +3285,15 @@ static int hpet_msi_set_affinity(struct irq_data *data,
 
        hpet_msi_write(data->handler_data, &msg);
 
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 
-#endif /* CONFIG_SMP */
-
 static struct irq_chip hpet_msi_type = {
        .name = "HPET_MSI",
        .irq_unmask = hpet_msi_unmask,
        .irq_mask = hpet_msi_mask,
        .irq_ack = ack_apic_edge,
-#ifdef CONFIG_SMP
        .irq_set_affinity = hpet_msi_set_affinity,
-#endif
        .irq_retrigger = ioapic_retrigger_irq,
 };
 
@@ -3314,8 +3328,6 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
  */
 #ifdef CONFIG_HT_IRQ
 
-#ifdef CONFIG_SMP
-
 static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
 {
        struct ht_irq_msg msg;
@@ -3340,25 +3352,23 @@ ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
                return -1;
 
        target_ht_irq(data->irq, dest, cfg->vector);
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 
-#endif
-
 static struct irq_chip ht_irq_chip = {
        .name                   = "PCI-HT",
        .irq_mask               = mask_ht_irq,
        .irq_unmask             = unmask_ht_irq,
        .irq_ack                = ack_apic_edge,
-#ifdef CONFIG_SMP
        .irq_set_affinity       = ht_set_affinity,
-#endif
        .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 {
        struct irq_cfg *cfg;
+       struct ht_irq_msg msg;
+       unsigned dest;
        int err;
 
        if (disable_apic)
@@ -3366,36 +3376,37 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 
        cfg = irq_cfg(irq);
        err = assign_irq_vector(irq, cfg, apic->target_cpus());
-       if (!err) {
-               struct ht_irq_msg msg;
-               unsigned dest;
+       if (err)
+               return err;
+
+       err = apic->cpu_mask_to_apicid_and(cfg->domain,
+                                          apic->target_cpus(), &dest);
+       if (err)
+               return err;
 
-               dest = apic->cpu_mask_to_apicid_and(cfg->domain,
-                                                   apic->target_cpus());
+       msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
 
-               msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
+       msg.address_lo =
+               HT_IRQ_LOW_BASE |
+               HT_IRQ_LOW_DEST_ID(dest) |
+               HT_IRQ_LOW_VECTOR(cfg->vector) |
+               ((apic->irq_dest_mode == 0) ?
+                       HT_IRQ_LOW_DM_PHYSICAL :
+                       HT_IRQ_LOW_DM_LOGICAL) |
+               HT_IRQ_LOW_RQEOI_EDGE |
+               ((apic->irq_delivery_mode != dest_LowestPrio) ?
+                       HT_IRQ_LOW_MT_FIXED :
+                       HT_IRQ_LOW_MT_ARBITRATED) |
+               HT_IRQ_LOW_IRQ_MASKED;
 
-               msg.address_lo =
-                       HT_IRQ_LOW_BASE |
-                       HT_IRQ_LOW_DEST_ID(dest) |
-                       HT_IRQ_LOW_VECTOR(cfg->vector) |
-                       ((apic->irq_dest_mode == 0) ?
-                               HT_IRQ_LOW_DM_PHYSICAL :
-                               HT_IRQ_LOW_DM_LOGICAL) |
-                       HT_IRQ_LOW_RQEOI_EDGE |
-                       ((apic->irq_delivery_mode != dest_LowestPrio) ?
-                               HT_IRQ_LOW_MT_FIXED :
-                               HT_IRQ_LOW_MT_ARBITRATED) |
-                       HT_IRQ_LOW_IRQ_MASKED;
+       write_ht_irq_msg(irq, &msg);
 
-               write_ht_irq_msg(irq, &msg);
+       irq_set_chip_and_handler_name(irq, &ht_irq_chip,
+                                     handle_edge_irq, "edge");
 
-               irq_set_chip_and_handler_name(irq, &ht_irq_chip,
-                                             handle_edge_irq, "edge");
+       dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
 
-               dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
-       }
-       return err;
+       return 0;
 }
 #endif /* CONFIG_HT_IRQ */
 
@@ -3563,7 +3574,8 @@ static int __init io_apic_get_unique_id(int ioapic, int apic_id)
 
                /* Sanity check */
                if (reg_00.bits.ID != apic_id) {
-                       printk("IOAPIC[%d]: Unable to change apic_id!\n", ioapic);
+                       pr_err("IOAPIC[%d]: Unable to change apic_id!\n",
+                              ioapic);
                        return -1;
                }
        }
index f00a68cca37a9bbd9ebc613b78fd4519e632cb4b..d661ee95cabfa0b2619b94f75971cfd33cd3ea7f 100644 (file)
@@ -406,16 +406,13 @@ static inline int numaq_check_phys_apicid_present(int phys_apicid)
  * We use physical apicids here, not logical, so just return the default
  * physical broadcast to stop people from breaking us
  */
-static unsigned int numaq_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-       return 0x0F;
-}
-
-static inline unsigned int
+static int
 numaq_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                            const struct cpumask *andmask)
+                            const struct cpumask *andmask,
+                            unsigned int *apicid)
 {
-       return 0x0F;
+       *apicid = 0x0F;
+       return 0;
 }
 
 /* No NUMA-Q box has a HT CPU, but it can't hurt to use the default code. */
@@ -441,20 +438,6 @@ static int probe_numaq(void)
        return found_numaq;
 }
 
-static void numaq_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       /* Careful. Some cpus do not strictly honor the set of cpus
-        * specified in the interrupt destination when using lowest
-        * priority interrupt delivery mode.
-        *
-        * In particular there was a hyperthreading cpu observed to
-        * deliver interrupts to the wrong hyperthread when only one
-        * hyperthread was specified in the interrupt desitination.
-        */
-       cpumask_clear(retmask);
-       cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 static void numaq_setup_portio_remap(void)
 {
        int num_quads = num_online_nodes();
@@ -491,7 +474,7 @@ static struct apic __refdata apic_numaq = {
        .check_apicid_used              = numaq_check_apicid_used,
        .check_apicid_present           = numaq_check_apicid_present,
 
-       .vector_allocation_domain       = numaq_vector_allocation_domain,
+       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = numaq_init_apic_ldr,
 
        .ioapic_phys_id_map             = numaq_ioapic_phys_id_map,
@@ -509,7 +492,6 @@ static struct apic __refdata apic_numaq = {
        .set_apic_id                    = NULL,
        .apic_id_mask                   = 0x0F << 24,
 
-       .cpu_mask_to_apicid             = numaq_cpu_mask_to_apicid,
        .cpu_mask_to_apicid_and         = numaq_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = numaq_send_IPI_mask,
index 1b291da09e6029750e0613c9b6b873d1bce2a6a6..eb35ef9ee63f779bde870822a01dcc98bd503b01 100644 (file)
@@ -66,21 +66,6 @@ static void setup_apic_flat_routing(void)
 #endif
 }
 
-static void default_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       /*
-        * Careful. Some cpus do not strictly honor the set of cpus
-        * specified in the interrupt destination when using lowest
-        * priority interrupt delivery mode.
-        *
-        * In particular there was a hyperthreading cpu observed to
-        * deliver interrupts to the wrong hyperthread when only one
-        * hyperthread was specified in the interrupt desitination.
-        */
-       cpumask_clear(retmask);
-       cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 /* should be called last. */
 static int probe_default(void)
 {
@@ -105,7 +90,7 @@ static struct apic apic_default = {
        .check_apicid_used              = default_check_apicid_used,
        .check_apicid_present           = default_check_apicid_present,
 
-       .vector_allocation_domain       = default_vector_allocation_domain,
+       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = default_init_apic_ldr,
 
        .ioapic_phys_id_map             = default_ioapic_phys_id_map,
@@ -123,8 +108,7 @@ static struct apic apic_default = {
        .set_apic_id                    = NULL,
        .apic_id_mask                   = 0x0F << 24,
 
-       .cpu_mask_to_apicid             = default_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid_and         = flat_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = default_send_IPI_mask_logical,
        .send_IPI_mask_allbutself       = default_send_IPI_mask_allbutself_logical,
@@ -208,6 +192,9 @@ void __init default_setup_apic_routing(void)
 
        if (apic->setup_apic_routing)
                apic->setup_apic_routing();
+
+       if (x86_platform.apic_post_init)
+               x86_platform.apic_post_init();
 }
 
 void __init generic_apic_probe(void)
index 3fe98669892905c48d3b8eea6ee11bda7100e75d..1793dba7a741bcf22271b71848fa92293bddde70 100644 (file)
 #include <asm/ipi.h>
 #include <asm/setup.h>
 
-static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
-{
-       return hard_smp_processor_id() >> index_msb;
-}
-
 /*
  * Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
  */
@@ -48,10 +43,8 @@ void __init default_setup_apic_routing(void)
                }
        }
 
-       if (is_vsmp_box()) {
-               /* need to update phys_pkg_id */
-               apic->phys_pkg_id = apicid_phys_pkg_id;
-       }
+       if (x86_platform.apic_post_init)
+               x86_platform.apic_post_init();
 }
 
 /* Same for both flat and physical. */
index 659897c007553916d129a5da1462b9e733cd6eff..77c95c0e1bf77d2ba06aa737ef22bebb8a0a1c22 100644 (file)
@@ -26,6 +26,8 @@
  *
  */
 
+#define pr_fmt(fmt) "summit: %s: " fmt, __func__
+
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <asm/io.h>
@@ -235,8 +237,8 @@ static int summit_apic_id_registered(void)
 
 static void summit_setup_apic_routing(void)
 {
-       printk("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
-                                               nr_ioapics);
+       pr_info("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
+               nr_ioapics);
 }
 
 static int summit_cpu_present_to_apicid(int mps_cpu)
@@ -263,43 +265,48 @@ static int summit_check_phys_apicid_present(int physical_apicid)
        return 1;
 }
 
-static unsigned int summit_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static inline int
+summit_cpu_mask_to_apicid(const struct cpumask *cpumask, unsigned int *dest_id)
 {
        unsigned int round = 0;
-       int cpu, apicid = 0;
+       unsigned int cpu, apicid = 0;
 
        /*
         * The cpus in the mask must all be on the apic cluster.
         */
-       for_each_cpu(cpu, cpumask) {
+       for_each_cpu_and(cpu, cpumask, cpu_online_mask) {
                int new_apicid = early_per_cpu(x86_cpu_to_logical_apicid, cpu);
 
                if (round && APIC_CLUSTER(apicid) != APIC_CLUSTER(new_apicid)) {
-                       printk("%s: Not a valid mask!\n", __func__);
-                       return BAD_APICID;
+                       pr_err("Not a valid mask!\n");
+                       return -EINVAL;
                }
                apicid |= new_apicid;
                round++;
        }
-       return apicid;
+       if (!round)
+               return -EINVAL;
+       *dest_id = apicid;
+       return 0;
 }
 
-static unsigned int summit_cpu_mask_to_apicid_and(const struct cpumask *inmask,
-                             const struct cpumask *andmask)
+static int
+summit_cpu_mask_to_apicid_and(const struct cpumask *inmask,
+                             const struct cpumask *andmask,
+                             unsigned int *apicid)
 {
-       int apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
        cpumask_var_t cpumask;
+       *apicid = early_per_cpu(x86_cpu_to_logical_apicid, 0);
 
        if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
-               return apicid;
+               return 0;
 
        cpumask_and(cpumask, inmask, andmask);
-       cpumask_and(cpumask, cpumask, cpu_online_mask);
-       apicid = summit_cpu_mask_to_apicid(cpumask);
+       summit_cpu_mask_to_apicid(cpumask, apicid);
 
        free_cpumask_var(cpumask);
 
-       return apicid;
+       return 0;
 }
 
 /*
@@ -320,20 +327,6 @@ static int probe_summit(void)
        return 0;
 }
 
-static void summit_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       /* Careful. Some cpus do not strictly honor the set of cpus
-        * specified in the interrupt destination when using lowest
-        * priority interrupt delivery mode.
-        *
-        * In particular there was a hyperthreading cpu observed to
-        * deliver interrupts to the wrong hyperthread when only one
-        * hyperthread was specified in the interrupt desitination.
-        */
-       cpumask_clear(retmask);
-       cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
-}
-
 #ifdef CONFIG_X86_SUMMIT_NUMA
 static struct rio_table_hdr *rio_table_hdr;
 static struct scal_detail   *scal_devs[MAX_NUMNODES];
@@ -355,7 +348,7 @@ static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
                }
        }
        if (i == rio_table_hdr->num_rio_dev) {
-               printk(KERN_ERR "%s: Couldn't find owner Cyclone for Winnipeg!\n", __func__);
+               pr_err("Couldn't find owner Cyclone for Winnipeg!\n");
                return last_bus;
        }
 
@@ -366,7 +359,7 @@ static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
                }
        }
        if (i == rio_table_hdr->num_scal_dev) {
-               printk(KERN_ERR "%s: Couldn't find owner Twister for Cyclone!\n", __func__);
+               pr_err("Couldn't find owner Twister for Cyclone!\n");
                return last_bus;
        }
 
@@ -396,7 +389,7 @@ static int setup_pci_node_map_for_wpeg(int wpeg_num, int last_bus)
                num_buses = 9;
                break;
        default:
-               printk(KERN_INFO "%s: Unsupported Winnipeg type!\n", __func__);
+               pr_info("Unsupported Winnipeg type!\n");
                return last_bus;
        }
 
@@ -411,13 +404,15 @@ static int build_detail_arrays(void)
        int i, scal_detail_size, rio_detail_size;
 
        if (rio_table_hdr->num_scal_dev > MAX_NUMNODES) {
-               printk(KERN_WARNING "%s: MAX_NUMNODES too low!  Defined as %d, but system has %d nodes.\n", __func__, MAX_NUMNODES, rio_table_hdr->num_scal_dev);
+               pr_warn("MAX_NUMNODES too low!  Defined as %d, but system has %d nodes\n",
+                       MAX_NUMNODES, rio_table_hdr->num_scal_dev);
                return 0;
        }
 
        switch (rio_table_hdr->version) {
        default:
-               printk(KERN_WARNING "%s: Invalid Rio Grande Table Version: %d\n", __func__, rio_table_hdr->version);
+               pr_warn("Invalid Rio Grande Table Version: %d\n",
+                       rio_table_hdr->version);
                return 0;
        case 2:
                scal_detail_size = 11;
@@ -462,7 +457,7 @@ void setup_summit(void)
                offset = *((unsigned short *)(ptr + offset));
        }
        if (!rio_table_hdr) {
-               printk(KERN_ERR "%s: Unable to locate Rio Grande Table in EBDA - bailing!\n", __func__);
+               pr_err("Unable to locate Rio Grande Table in EBDA - bailing!\n");
                return;
        }
 
@@ -509,7 +504,7 @@ static struct apic apic_summit = {
        .check_apicid_used              = summit_check_apicid_used,
        .check_apicid_present           = summit_check_apicid_present,
 
-       .vector_allocation_domain       = summit_vector_allocation_domain,
+       .vector_allocation_domain       = flat_vector_allocation_domain,
        .init_apic_ldr                  = summit_init_apic_ldr,
 
        .ioapic_phys_id_map             = summit_ioapic_phys_id_map,
@@ -527,7 +522,6 @@ static struct apic apic_summit = {
        .set_apic_id                    = NULL,
        .apic_id_mask                   = 0xFF << 24,
 
-       .cpu_mask_to_apicid             = summit_cpu_mask_to_apicid,
        .cpu_mask_to_apicid_and         = summit_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = summit_send_IPI_mask,
index ff35cff0e1a7e6f4f16b628504c821c5e544bacf..c88baa4ff0e5650061dbed84fca55b89d4c1b55e 100644 (file)
@@ -81,7 +81,7 @@ static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
 }
 
 static void
- x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
+x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
 {
        __x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
 }
@@ -96,36 +96,37 @@ static void x2apic_send_IPI_all(int vector)
        __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
 }
 
-static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
+static int
+x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
+                             const struct cpumask *andmask,
+                             unsigned int *apicid)
 {
-       /*
-        * We're using fixed IRQ delivery, can only return one logical APIC ID.
-        * May as well be the first.
-        */
-       int cpu = cpumask_first(cpumask);
+       u32 dest = 0;
+       u16 cluster;
+       int i;
 
-       if ((unsigned)cpu < nr_cpu_ids)
-               return per_cpu(x86_cpu_to_logical_apicid, cpu);
-       else
-               return BAD_APICID;
-}
+       for_each_cpu_and(i, cpumask, andmask) {
+               if (!cpumask_test_cpu(i, cpu_online_mask))
+                       continue;
+               dest = per_cpu(x86_cpu_to_logical_apicid, i);
+               cluster = x2apic_cluster(i);
+               break;
+       }
 
-static unsigned int
-x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                             const struct cpumask *andmask)
-{
-       int cpu;
+       if (!dest)
+               return -EINVAL;
 
-       /*
-        * We're using fixed IRQ delivery, can only return one logical APIC ID.
-        * May as well be the first.
-        */
-       for_each_cpu_and(cpu, cpumask, andmask) {
-               if (cpumask_test_cpu(cpu, cpu_online_mask))
-                       break;
+       for_each_cpu_and(i, cpumask, andmask) {
+               if (!cpumask_test_cpu(i, cpu_online_mask))
+                       continue;
+               if (cluster != x2apic_cluster(i))
+                       continue;
+               dest |= per_cpu(x86_cpu_to_logical_apicid, i);
        }
 
-       return per_cpu(x86_cpu_to_logical_apicid, cpu);
+       *apicid = dest;
+
+       return 0;
 }
 
 static void init_x2apic_ldr(void)
@@ -208,6 +209,32 @@ static int x2apic_cluster_probe(void)
                return 0;
 }
 
+static const struct cpumask *x2apic_cluster_target_cpus(void)
+{
+       return cpu_all_mask;
+}
+
+/*
+ * Each x2apic cluster is an allocation domain.
+ */
+static void cluster_vector_allocation_domain(int cpu, struct cpumask *retmask,
+                                            const struct cpumask *mask)
+{
+       /*
+        * To minimize vector pressure, default case of boot, device bringup
+        * etc will use a single cpu for the interrupt destination.
+        *
+        * On explicit migration requests coming from irqbalance etc,
+        * interrupts will be routed to the x2apic cluster (cluster-id
+        * derived from the first cpu in the mask) members specified
+        * in the mask.
+        */
+       if (mask == x2apic_cluster_target_cpus())
+               cpumask_copy(retmask, cpumask_of(cpu));
+       else
+               cpumask_and(retmask, mask, per_cpu(cpus_in_cluster, cpu));
+}
+
 static struct apic apic_x2apic_cluster = {
 
        .name                           = "cluster x2apic",
@@ -219,13 +246,13 @@ static struct apic apic_x2apic_cluster = {
        .irq_delivery_mode              = dest_LowestPrio,
        .irq_dest_mode                  = 1, /* logical */
 
-       .target_cpus                    = x2apic_target_cpus,
+       .target_cpus                    = x2apic_cluster_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = NULL,
        .check_apicid_present           = NULL,
 
-       .vector_allocation_domain       = x2apic_vector_allocation_domain,
+       .vector_allocation_domain       = cluster_vector_allocation_domain,
        .init_apic_ldr                  = init_x2apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -243,7 +270,6 @@ static struct apic apic_x2apic_cluster = {
        .set_apic_id                    = x2apic_set_apic_id,
        .apic_id_mask                   = 0xFFFFFFFFu,
 
-       .cpu_mask_to_apicid             = x2apic_cpu_mask_to_apicid,
        .cpu_mask_to_apicid_and         = x2apic_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = x2apic_send_IPI_mask,
index c17e982db2759ad5913e8c586a7100267f014c32..e03a1e180e81789bb334918f7f92c2886142d491 100644 (file)
@@ -76,38 +76,6 @@ static void x2apic_send_IPI_all(int vector)
        __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
 }
 
-static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       int cpu = cpumask_first(cpumask);
-
-       if ((unsigned)cpu < nr_cpu_ids)
-               return per_cpu(x86_cpu_to_apicid, cpu);
-       else
-               return BAD_APICID;
-}
-
-static unsigned int
-x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                             const struct cpumask *andmask)
-{
-       int cpu;
-
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       for_each_cpu_and(cpu, cpumask, andmask) {
-               if (cpumask_test_cpu(cpu, cpu_online_mask))
-                       break;
-       }
-
-       return per_cpu(x86_cpu_to_apicid, cpu);
-}
-
 static void init_x2apic_ldr(void)
 {
 }
@@ -131,13 +99,13 @@ static struct apic apic_x2apic_phys = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = x2apic_target_cpus,
+       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = 0,
        .check_apicid_used              = NULL,
        .check_apicid_present           = NULL,
 
-       .vector_allocation_domain       = x2apic_vector_allocation_domain,
+       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = init_x2apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -155,8 +123,7 @@ static struct apic apic_x2apic_phys = {
        .set_apic_id                    = x2apic_set_apic_id,
        .apic_id_mask                   = 0xFFFFFFFFu,
 
-       .cpu_mask_to_apicid             = x2apic_cpu_mask_to_apicid,
-       .cpu_mask_to_apicid_and         = x2apic_cpu_mask_to_apicid_and,
+       .cpu_mask_to_apicid_and         = default_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = x2apic_send_IPI_mask,
        .send_IPI_mask_allbutself       = x2apic_send_IPI_mask_allbutself,
index c6d03f7a4401324444d33c0adf201ec13fbb7aea..8cfade9510a41b10a03a8964a6ff9ed7c914cb2f 100644 (file)
@@ -185,17 +185,6 @@ EXPORT_SYMBOL_GPL(uv_possible_blades);
 unsigned long sn_rtc_cycles_per_second;
 EXPORT_SYMBOL(sn_rtc_cycles_per_second);
 
-static const struct cpumask *uv_target_cpus(void)
-{
-       return cpu_online_mask;
-}
-
-static void uv_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
-       cpumask_clear(retmask);
-       cpumask_set_cpu(cpu, retmask);
-}
-
 static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_rip)
 {
 #ifdef CONFIG_SMP
@@ -280,25 +269,12 @@ static void uv_init_apic_ldr(void)
 {
 }
 
-static unsigned int uv_cpu_mask_to_apicid(const struct cpumask *cpumask)
-{
-       /*
-        * We're using fixed IRQ delivery, can only return one phys APIC ID.
-        * May as well be the first.
-        */
-       int cpu = cpumask_first(cpumask);
-
-       if ((unsigned)cpu < nr_cpu_ids)
-               return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
-       else
-               return BAD_APICID;
-}
-
-static unsigned int
+static int
 uv_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
-                         const struct cpumask *andmask)
+                         const struct cpumask *andmask,
+                         unsigned int *apicid)
 {
-       int cpu;
+       int unsigned cpu;
 
        /*
         * We're using fixed IRQ delivery, can only return one phys APIC ID.
@@ -308,7 +284,13 @@ uv_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
                if (cpumask_test_cpu(cpu, cpu_online_mask))
                        break;
        }
-       return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
+
+       if (likely(cpu < nr_cpu_ids)) {
+               *apicid = per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
+               return 0;
+       }
+
+       return -EINVAL;
 }
 
 static unsigned int x2apic_get_apic_id(unsigned long x)
@@ -362,13 +344,13 @@ static struct apic __refdata apic_x2apic_uv_x = {
        .irq_delivery_mode              = dest_Fixed,
        .irq_dest_mode                  = 0, /* physical */
 
-       .target_cpus                    = uv_target_cpus,
+       .target_cpus                    = online_target_cpus,
        .disable_esr                    = 0,
        .dest_logical                   = APIC_DEST_LOGICAL,
        .check_apicid_used              = NULL,
        .check_apicid_present           = NULL,
 
-       .vector_allocation_domain       = uv_vector_allocation_domain,
+       .vector_allocation_domain       = default_vector_allocation_domain,
        .init_apic_ldr                  = uv_init_apic_ldr,
 
        .ioapic_phys_id_map             = NULL,
@@ -386,7 +368,6 @@ static struct apic __refdata apic_x2apic_uv_x = {
        .set_apic_id                    = set_apic_id,
        .apic_id_mask                   = 0xFFFFFFFFu,
 
-       .cpu_mask_to_apicid             = uv_cpu_mask_to_apicid,
        .cpu_mask_to_apicid_and         = uv_cpu_mask_to_apicid_and,
 
        .send_IPI_mask                  = uv_send_IPI_mask,
index 07b0c0db466c4d794cf206358ced2b5e2c2b9e6b..d65464e4350343c9d379aa6d44a1ed03a1ca1f2c 100644 (file)
  *    http://www.microsoft.com/whdc/archive/amp_12.mspx]
  */
 
+#define pr_fmt(fmt) "apm: " fmt
+
 #include <linux/module.h>
 
 #include <linux/poll.h>
@@ -485,11 +487,11 @@ static void apm_error(char *str, int err)
                if (error_table[i].key == err)
                        break;
        if (i < ERROR_COUNT)
-               printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
+               pr_notice("%s: %s\n", str, error_table[i].msg);
        else if (err < 0)
-               printk(KERN_NOTICE "apm: %s: linux error code %i\n", str, err);
+               pr_notice("%s: linux error code %i\n", str, err);
        else
-               printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
+               pr_notice("%s: unknown error code %#2.2x\n",
                       str, err);
 }
 
@@ -1184,7 +1186,7 @@ static void queue_event(apm_event_t event, struct apm_user *sender)
                        static int notified;
 
                        if (notified++ == 0)
-                           printk(KERN_ERR "apm: an event queue overflowed\n");
+                               pr_err("an event queue overflowed\n");
                        if (++as->event_tail >= APM_MAX_EVENTS)
                                as->event_tail = 0;
                }
@@ -1447,7 +1449,7 @@ static void apm_mainloop(void)
 static int check_apm_user(struct apm_user *as, const char *func)
 {
        if (as == NULL || as->magic != APM_BIOS_MAGIC) {
-               printk(KERN_ERR "apm: %s passed bad filp\n", func);
+               pr_err("%s passed bad filp\n", func);
                return 1;
        }
        return 0;
@@ -1586,7 +1588,7 @@ static int do_release(struct inode *inode, struct file *filp)
                     as1 = as1->next)
                        ;
                if (as1 == NULL)
-                       printk(KERN_ERR "apm: filp not in user list\n");
+                       pr_err("filp not in user list\n");
                else
                        as1->next = as->next;
        }
@@ -1600,11 +1602,9 @@ static int do_open(struct inode *inode, struct file *filp)
        struct apm_user *as;
 
        as = kmalloc(sizeof(*as), GFP_KERNEL);
-       if (as == NULL) {
-               printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
-                      sizeof(*as));
+       if (as == NULL)
                return -ENOMEM;
-       }
+
        as->magic = APM_BIOS_MAGIC;
        as->event_tail = as->event_head = 0;
        as->suspends_pending = as->standbys_pending = 0;
@@ -2313,16 +2313,16 @@ static int __init apm_init(void)
        }
 
        if (apm_info.disabled) {
-               printk(KERN_NOTICE "apm: disabled on user request.\n");
+               pr_notice("disabled on user request.\n");
                return -ENODEV;
        }
        if ((num_online_cpus() > 1) && !power_off && !smp) {
-               printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+               pr_notice("disabled - APM is not SMP safe.\n");
                apm_info.disabled = 1;
                return -ENODEV;
        }
        if (!acpi_disabled) {
-               printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+               pr_notice("overridden by ACPI.\n");
                apm_info.disabled = 1;
                return -ENODEV;
        }
@@ -2356,8 +2356,7 @@ static int __init apm_init(void)
 
        kapmd_task = kthread_create(apm, NULL, "kapmd");
        if (IS_ERR(kapmd_task)) {
-               printk(KERN_ERR "apm: disabled - Unable to start kernel "
-                               "thread.\n");
+               pr_err("disabled - Unable to start kernel thread\n");
                err = PTR_ERR(kapmd_task);
                kapmd_task = NULL;
                remove_proc_entry("apm", NULL);
index 6ab6aa2fdfdd21ef0192b0eb11a99c1a0531f8ab..bac4c3804cc7530e179630e87facca153576d026 100644 (file)
@@ -32,7 +32,9 @@ obj-$(CONFIG_PERF_EVENTS)             += perf_event.o
 
 ifdef CONFIG_PERF_EVENTS
 obj-$(CONFIG_CPU_SUP_AMD)              += perf_event_amd.o
-obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_p6.o perf_event_p4.o perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_p6.o perf_event_p4.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
+obj-$(CONFIG_CPU_SUP_INTEL)            += perf_event_intel_uncore.o
 endif
 
 obj-$(CONFIG_X86_MCE)                  += mcheck/
index 146bb6218eec3daa3cdbe0472c04bcfac7500e8a..9d92e19039f05f84b4c172de7c1c243a4dad72e0 100644 (file)
 
 #include "cpu.h"
 
+static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
+{
+       struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+       u32 gprs[8] = { 0 };
+       int err;
+
+       WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
+
+       gprs[1] = msr;
+       gprs[7] = 0x9c5a203a;
+
+       err = rdmsr_safe_regs(gprs);
+
+       *p = gprs[0] | ((u64)gprs[2] << 32);
+
+       return err;
+}
+
+static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
+{
+       struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
+       u32 gprs[8] = { 0 };
+
+       WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
+
+       gprs[0] = (u32)val;
+       gprs[1] = msr;
+       gprs[2] = val >> 32;
+       gprs[7] = 0x9c5a203a;
+
+       return wrmsr_safe_regs(gprs);
+}
+
 #ifdef CONFIG_X86_32
 /*
  *     B step AMD K6 before B 9730xxxx have hardware bugs that can cause
@@ -586,9 +619,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
            !cpu_has(c, X86_FEATURE_TOPOEXT)) {
                u64 val;
 
-               if (!rdmsrl_amd_safe(0xc0011005, &val)) {
+               if (!rdmsrl_safe(0xc0011005, &val)) {
                        val |= 1ULL << 54;
-                       wrmsrl_amd_safe(0xc0011005, val);
+                       wrmsrl_safe(0xc0011005, val);
                        rdmsrl(0xc0011005, val);
                        if (val & (1ULL << 54)) {
                                set_cpu_cap(c, X86_FEATURE_TOPOEXT);
@@ -679,7 +712,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
                err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask);
                if (err == 0) {
                        mask |= (1 << 10);
-                       checking_wrmsrl(MSR_AMD64_MCx_MASK(4), mask);
+                       wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask);
                }
        }
 
index 46674fbb62baac1826c8b23b43903630909ce579..c97bb7b5a9f878332e81d119bae0a571c17d8ea0 100644 (file)
@@ -55,8 +55,8 @@ static void __init check_fpu(void)
 
        if (!boot_cpu_data.hard_math) {
 #ifndef CONFIG_MATH_EMULATION
-               printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
-               printk(KERN_EMERG "Giving up.\n");
+               pr_emerg("No coprocessor found and no math emulation present\n");
+               pr_emerg("Giving up\n");
                for (;;) ;
 #endif
                return;
@@ -86,7 +86,7 @@ static void __init check_fpu(void)
 
        boot_cpu_data.fdiv_bug = fdiv_bug;
        if (boot_cpu_data.fdiv_bug)
-               printk(KERN_WARNING "Hmm, FPU with FDIV bug.\n");
+               pr_warn("Hmm, FPU with FDIV bug\n");
 }
 
 static void __init check_hlt(void)
@@ -94,16 +94,16 @@ static void __init check_hlt(void)
        if (boot_cpu_data.x86 >= 5 || paravirt_enabled())
                return;
 
-       printk(KERN_INFO "Checking 'hlt' instruction... ");
+       pr_info("Checking 'hlt' instruction... ");
        if (!boot_cpu_data.hlt_works_ok) {
-               printk("disabled\n");
+               pr_cont("disabled\n");
                return;
        }
        halt();
        halt();
        halt();
        halt();
-       printk(KERN_CONT "OK.\n");
+       pr_cont("OK\n");
 }
 
 /*
@@ -116,7 +116,7 @@ static void __init check_popad(void)
 #ifndef CONFIG_X86_POPAD_OK
        int res, inp = (int) &res;
 
-       printk(KERN_INFO "Checking for popad bug... ");
+       pr_info("Checking for popad bug... ");
        __asm__ __volatile__(
          "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
          : "=&a" (res)
@@ -127,9 +127,9 @@ static void __init check_popad(void)
         * CPU hard. Too bad.
         */
        if (res != 12345678)
-               printk(KERN_CONT "Buggy.\n");
+               pr_cont("Buggy\n");
        else
-               printk(KERN_CONT "OK.\n");
+               pr_cont("OK\n");
 #endif
 }
 
@@ -161,7 +161,7 @@ void __init check_bugs(void)
 {
        identify_boot_cpu();
 #ifndef CONFIG_SMP
-       printk(KERN_INFO "CPU: ");
+       pr_info("CPU: ");
        print_cpu_info(&boot_cpu_data);
 #endif
        check_config();
index 6b9333b429ba1910637bf29c63bbe0712064022e..5bbc082c47ad8d1fef9950c5dda873f1fdd5975c 100644 (file)
@@ -947,7 +947,7 @@ static void __cpuinit __print_cpu_msr(void)
                index_max = msr_range_array[i].max;
 
                for (index = index_min; index < index_max; index++) {
-                       if (rdmsrl_amd_safe(index, &val))
+                       if (rdmsrl_safe(index, &val))
                                continue;
                        printk(KERN_INFO " MSR%08x: %016llx\n", index, val);
                }
index da27c5d2168a74c29e3d1da16d108ef7017113c8..9473e8772fd19bba99ac568a2d7afda3af86aa6f 100644 (file)
@@ -7,6 +7,9 @@
  * Copyright 2008 Intel Corporation
  * Author: Andi Kleen
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/thread_info.h>
 #include <linux/capability.h>
 #include <linux/miscdevice.h>
@@ -210,7 +213,7 @@ static void drain_mcelog_buffer(void)
                                cpu_relax();
 
                                if (!m->finished && retries >= 4) {
-                                       pr_err("MCE: skipping error being logged currently!\n");
+                                       pr_err("skipping error being logged currently!\n");
                                        break;
                                }
                        }
@@ -1167,8 +1170,9 @@ int memory_failure(unsigned long pfn, int vector, int flags)
 {
        /* mce_severity() should not hand us an ACTION_REQUIRED error */
        BUG_ON(flags & MF_ACTION_REQUIRED);
-       printk(KERN_ERR "Uncorrected memory error in page 0x%lx ignored\n"
-               "Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n", pfn);
+       pr_err("Uncorrected memory error in page 0x%lx ignored\n"
+              "Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n",
+              pfn);
 
        return 0;
 }
@@ -1186,6 +1190,7 @@ void mce_notify_process(void)
 {
        unsigned long pfn;
        struct mce_info *mi = mce_find_info();
+       int flags = MF_ACTION_REQUIRED;
 
        if (!mi)
                mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL);
@@ -1200,8 +1205,9 @@ void mce_notify_process(void)
         * doomed. We still need to mark the page as poisoned and alert any
         * other users of the page.
         */
-       if (memory_failure(pfn, MCE_VECTOR, MF_ACTION_REQUIRED) < 0 ||
-                          mi->restartable == 0) {
+       if (!mi->restartable)
+               flags |= MF_MUST_KILL;
+       if (memory_failure(pfn, MCE_VECTOR, flags) < 0) {
                pr_err("Memory error not recovered");
                force_sig(SIGBUS, current);
        }
@@ -1358,11 +1364,10 @@ static int __cpuinit __mcheck_cpu_cap_init(void)
 
        b = cap & MCG_BANKCNT_MASK;
        if (!banks)
-               printk(KERN_INFO "mce: CPU supports %d MCE banks\n", b);
+               pr_info("CPU supports %d MCE banks\n", b);
 
        if (b > MAX_NR_BANKS) {
-               printk(KERN_WARNING
-                      "MCE: Using only %u machine check banks out of %u\n",
+               pr_warn("Using only %u machine check banks out of %u\n",
                        MAX_NR_BANKS, b);
                b = MAX_NR_BANKS;
        }
@@ -1419,7 +1424,7 @@ static void __mcheck_cpu_init_generic(void)
 static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
 {
        if (c->x86_vendor == X86_VENDOR_UNKNOWN) {
-               pr_info("MCE: unknown CPU type - not enabling MCE support.\n");
+               pr_info("unknown CPU type - not enabling MCE support\n");
                return -EOPNOTSUPP;
        }
 
@@ -1574,7 +1579,7 @@ static void __mcheck_cpu_init_timer(void)
 /* Handle unconfigured int18 (should never happen) */
 static void unexpected_machine_check(struct pt_regs *regs, long error_code)
 {
-       printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n",
+       pr_err("CPU#%d: Unexpected int18 (Machine Check)\n",
               smp_processor_id());
 }
 
@@ -1893,8 +1898,7 @@ static int __init mcheck_enable(char *str)
                        get_option(&str, &monarch_timeout);
                }
        } else {
-               printk(KERN_INFO "mce argument %s ignored. Please use /sys\n",
-                      str);
+               pr_info("mce argument %s ignored. Please use /sys\n", str);
                return 0;
        }
        return 1;
index f4873a64f46dcb2dac8db0c3585afecc642e70ee..671b95a2ffb5fd45381e59f1a3e1198f5a46e834 100644 (file)
@@ -1,15 +1,17 @@
 /*
- *  (c) 2005, 2006 Advanced Micro Devices, Inc.
+ *  (c) 2005-2012 Advanced Micro Devices, Inc.
  *  Your use of this code is subject to the terms and conditions of the
  *  GNU general public license version 2. See "COPYING" or
  *  http://www.gnu.org/licenses/gpl.html
  *
  *  Written by Jacob Shin - AMD, Inc.
  *
- *  Support : jacob.shin@amd.com
+ *  Support: borislav.petkov@amd.com
  *
  *  April 2006
  *     - added support for AMD Family 0x10 processors
+ *  May 2012
+ *     - major scrubbing
  *
  *  All MC4_MISCi registers are shared between multi-cores
  */
@@ -25,6 +27,7 @@
 #include <linux/cpu.h>
 #include <linux/smp.h>
 
+#include <asm/amd_nb.h>
 #include <asm/apic.h>
 #include <asm/idle.h>
 #include <asm/mce.h>
 #define MASK_BLKPTR_LO    0xFF000000
 #define MCG_XBLK_ADDR     0xC0000400
 
-struct threshold_block {
-       unsigned int            block;
-       unsigned int            bank;
-       unsigned int            cpu;
-       u32                     address;
-       u16                     interrupt_enable;
-       bool                    interrupt_capable;
-       u16                     threshold_limit;
-       struct kobject          kobj;
-       struct list_head        miscj;
+static const char * const th_names[] = {
+       "load_store",
+       "insn_fetch",
+       "combined_unit",
+       "",
+       "northbridge",
+       "execution_unit",
 };
 
-struct threshold_bank {
-       struct kobject          *kobj;
-       struct threshold_block  *blocks;
-       cpumask_var_t           cpus;
-};
 static DEFINE_PER_CPU(struct threshold_bank * [NR_BANKS], threshold_banks);
 
 static unsigned char shared_bank[NR_BANKS] = {
@@ -84,6 +79,26 @@ struct thresh_restart {
        u16                     old_limit;
 };
 
+static const char * const bank4_names(struct threshold_block *b)
+{
+       switch (b->address) {
+       /* MSR4_MISC0 */
+       case 0x00000413:
+               return "dram";
+
+       case 0xc0000408:
+               return "ht_links";
+
+       case 0xc0000409:
+               return "l3_cache";
+
+       default:
+               WARN(1, "Funny MSR: 0x%08x\n", b->address);
+               return "";
+       }
+};
+
+
 static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
 {
        /*
@@ -224,8 +239,6 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
 
                        if (!block)
                                per_cpu(bank_map, cpu) |= (1 << bank);
-                       if (shared_bank[bank] && c->cpu_core_id)
-                               break;
 
                        memset(&b, 0, sizeof(b));
                        b.cpu                   = cpu;
@@ -326,7 +339,7 @@ struct threshold_attr {
 #define SHOW_FIELDS(name)                                              \
 static ssize_t show_ ## name(struct threshold_block *b, char *buf)     \
 {                                                                      \
-       return sprintf(buf, "%lx\n", (unsigned long) b->name);          \
+       return sprintf(buf, "%lu\n", (unsigned long) b->name);          \
 }
 SHOW_FIELDS(interrupt_enable)
 SHOW_FIELDS(threshold_limit)
@@ -377,38 +390,21 @@ store_threshold_limit(struct threshold_block *b, const char *buf, size_t size)
        return size;
 }
 
-struct threshold_block_cross_cpu {
-       struct threshold_block  *tb;
-       long                    retval;
-};
-
-static void local_error_count_handler(void *_tbcc)
-{
-       struct threshold_block_cross_cpu *tbcc = _tbcc;
-       struct threshold_block *b = tbcc->tb;
-       u32 low, high;
-
-       rdmsr(b->address, low, high);
-       tbcc->retval = (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit);
-}
-
 static ssize_t show_error_count(struct threshold_block *b, char *buf)
 {
-       struct threshold_block_cross_cpu tbcc = { .tb = b, };
+       u32 lo, hi;
 
-       smp_call_function_single(b->cpu, local_error_count_handler, &tbcc, 1);
-       return sprintf(buf, "%lx\n", tbcc.retval);
-}
+       rdmsr_on_cpu(b->cpu, b->address, &lo, &hi);
 
-static ssize_t store_error_count(struct threshold_block *b,
-                                const char *buf, size_t count)
-{
-       struct thresh_restart tr = { .b = b, .reset = 1, .old_limit = 0 };
-
-       smp_call_function_single(b->cpu, threshold_restart_bank, &tr, 1);
-       return 1;
+       return sprintf(buf, "%u\n", ((hi & THRESHOLD_MAX) -
+                                    (THRESHOLD_MAX - b->threshold_limit)));
 }
 
+static struct threshold_attr error_count = {
+       .attr = {.name = __stringify(error_count), .mode = 0444 },
+       .show = show_error_count,
+};
+
 #define RW_ATTR(val)                                                   \
 static struct threshold_attr val = {                                   \
        .attr   = {.name = __stringify(val), .mode = 0644 },            \
@@ -418,7 +414,6 @@ static struct threshold_attr val = {                                        \
 
 RW_ATTR(interrupt_enable);
 RW_ATTR(threshold_limit);
-RW_ATTR(error_count);
 
 static struct attribute *default_attrs[] = {
        &threshold_limit.attr,
@@ -517,7 +512,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
 
        err = kobject_init_and_add(&b->kobj, &threshold_ktype,
                                   per_cpu(threshold_banks, cpu)[bank]->kobj,
-                                  "misc%i", block);
+                                  (bank == 4 ? bank4_names(b) : th_names[bank]));
        if (err)
                goto out_free;
 recurse:
@@ -548,98 +543,91 @@ out_free:
        return err;
 }
 
-static __cpuinit long
-local_allocate_threshold_blocks(int cpu, unsigned int bank)
+static __cpuinit int __threshold_add_blocks(struct threshold_bank *b)
 {
-       return allocate_threshold_blocks(cpu, bank, 0,
-                                        MSR_IA32_MC0_MISC + bank * 4);
+       struct list_head *head = &b->blocks->miscj;
+       struct threshold_block *pos = NULL;
+       struct threshold_block *tmp = NULL;
+       int err = 0;
+
+       err = kobject_add(&b->blocks->kobj, b->kobj, b->blocks->kobj.name);
+       if (err)
+               return err;
+
+       list_for_each_entry_safe(pos, tmp, head, miscj) {
+
+               err = kobject_add(&pos->kobj, b->kobj, pos->kobj.name);
+               if (err) {
+                       list_for_each_entry_safe_reverse(pos, tmp, head, miscj)
+                               kobject_del(&pos->kobj);
+
+                       return err;
+               }
+       }
+       return err;
 }
 
-/* symlinks sibling shared banks to first core.  first core owns dir/files. */
 static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
 {
-       int i, err = 0;
-       struct threshold_bank *b = NULL;
        struct device *dev = per_cpu(mce_device, cpu);
-       char name[32];
-
-       sprintf(name, "threshold_bank%i", bank);
+       struct amd_northbridge *nb = NULL;
+       struct threshold_bank *b = NULL;
+       const char *name = th_names[bank];
+       int err = 0;
 
-#ifdef CONFIG_SMP
-       if (cpu_data(cpu).cpu_core_id && shared_bank[bank]) {   /* symlink */
-               i = cpumask_first(cpu_llc_shared_mask(cpu));
+       if (shared_bank[bank]) {
 
-               /* first core not up yet */
-               if (cpu_data(i).cpu_core_id)
-                       goto out;
+               nb = node_to_amd_nb(amd_get_nb_id(cpu));
+               WARN_ON(!nb);
 
-               /* already linked */
-               if (per_cpu(threshold_banks, cpu)[bank])
-                       goto out;
+               /* threshold descriptor already initialized on this node? */
+               if (nb->bank4) {
+                       /* yes, use it */
+                       b = nb->bank4;
+                       err = kobject_add(b->kobj, &dev->kobj, name);
+                       if (err)
+                               goto out;
 
-               b = per_cpu(threshold_banks, i)[bank];
+                       per_cpu(threshold_banks, cpu)[bank] = b;
+                       atomic_inc(&b->cpus);
 
-               if (!b)
-                       goto out;
+                       err = __threshold_add_blocks(b);
 
-               err = sysfs_create_link(&dev->kobj, b->kobj, name);
-               if (err)
                        goto out;
-
-               cpumask_copy(b->cpus, cpu_llc_shared_mask(cpu));
-               per_cpu(threshold_banks, cpu)[bank] = b;
-
-               goto out;
+               }
        }
-#endif
 
        b = kzalloc(sizeof(struct threshold_bank), GFP_KERNEL);
        if (!b) {
                err = -ENOMEM;
                goto out;
        }
-       if (!zalloc_cpumask_var(&b->cpus, GFP_KERNEL)) {
-               kfree(b);
-               err = -ENOMEM;
-               goto out;
-       }
 
        b->kobj = kobject_create_and_add(name, &dev->kobj);
-       if (!b->kobj)
+       if (!b->kobj) {
+               err = -EINVAL;
                goto out_free;
-
-#ifndef CONFIG_SMP
-       cpumask_setall(b->cpus);
-#else
-       cpumask_set_cpu(cpu, b->cpus);
-#endif
+       }
 
        per_cpu(threshold_banks, cpu)[bank] = b;
 
-       err = local_allocate_threshold_blocks(cpu, bank);
-       if (err)
-               goto out_free;
-
-       for_each_cpu(i, b->cpus) {
-               if (i == cpu)
-                       continue;
+       if (shared_bank[bank]) {
+               atomic_set(&b->cpus, 1);
 
-               dev = per_cpu(mce_device, i);
-               if (dev)
-                       err = sysfs_create_link(&dev->kobj,b->kobj, name);
-               if (err)
-                       goto out;
-
-               per_cpu(threshold_banks, i)[bank] = b;
+               /* nb is already initialized, see above */
+               WARN_ON(nb->bank4);
+               nb->bank4 = b;
        }
 
-       goto out;
+       err = allocate_threshold_blocks(cpu, bank, 0,
+                                       MSR_IA32_MC0_MISC + bank * 4);
+       if (!err)
+               goto out;
 
-out_free:
-       per_cpu(threshold_banks, cpu)[bank] = NULL;
-       free_cpumask_var(b->cpus);
+ out_free:
        kfree(b);
-out:
+
+ out:
        return err;
 }
 
@@ -660,12 +648,6 @@ static __cpuinit int threshold_create_device(unsigned int cpu)
        return err;
 }
 
-/*
- * let's be hotplug friendly.
- * in case of multiple core processors, the first core always takes ownership
- *   of shared sysfs dir/files, and rest of the cores will be symlinked to it.
- */
-
 static void deallocate_threshold_block(unsigned int cpu,
                                                 unsigned int bank)
 {
@@ -686,41 +668,42 @@ static void deallocate_threshold_block(unsigned int cpu,
        per_cpu(threshold_banks, cpu)[bank]->blocks = NULL;
 }
 
+static void __threshold_remove_blocks(struct threshold_bank *b)
+{
+       struct threshold_block *pos = NULL;
+       struct threshold_block *tmp = NULL;
+
+       kobject_del(b->kobj);
+
+       list_for_each_entry_safe(pos, tmp, &b->blocks->miscj, miscj)
+               kobject_del(&pos->kobj);
+}
+
 static void threshold_remove_bank(unsigned int cpu, int bank)
 {
+       struct amd_northbridge *nb;
        struct threshold_bank *b;
-       struct device *dev;
-       char name[32];
-       int i = 0;
 
        b = per_cpu(threshold_banks, cpu)[bank];
        if (!b)
                return;
+
        if (!b->blocks)
                goto free_out;
 
-       sprintf(name, "threshold_bank%i", bank);
-
-#ifdef CONFIG_SMP
-       /* sibling symlink */
-       if (shared_bank[bank] && b->blocks->cpu != cpu) {
-               dev = per_cpu(mce_device, cpu);
-               sysfs_remove_link(&dev->kobj, name);
-               per_cpu(threshold_banks, cpu)[bank] = NULL;
-
-               return;
-       }
-#endif
-
-       /* remove all sibling symlinks before unregistering */
-       for_each_cpu(i, b->cpus) {
-               if (i == cpu)
-                       continue;
-
-               dev = per_cpu(mce_device, i);
-               if (dev)
-                       sysfs_remove_link(&dev->kobj, name);
-               per_cpu(threshold_banks, i)[bank] = NULL;
+       if (shared_bank[bank]) {
+               if (!atomic_dec_and_test(&b->cpus)) {
+                       __threshold_remove_blocks(b);
+                       per_cpu(threshold_banks, cpu)[bank] = NULL;
+                       return;
+               } else {
+                       /*
+                        * the last CPU on this node using the shared bank is
+                        * going away, remove that bank now.
+                        */
+                       nb = node_to_amd_nb(amd_get_nb_id(cpu));
+                       nb->bank4 = NULL;
+               }
        }
 
        deallocate_threshold_block(cpu, bank);
@@ -728,7 +711,6 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
 free_out:
        kobject_del(b->kobj);
        kobject_put(b->kobj);
-       free_cpumask_var(b->cpus);
        kfree(b);
        per_cpu(threshold_banks, cpu)[bank] = NULL;
 }
index bdda2e6c673bf71afb30ed670071a9d02dbdcbfa..35ffda5d0727d19b11cccccdde0e0d461b9e15ee 100644 (file)
@@ -258,11 +258,11 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk,
 
                /* Compute the maximum size with which we can make a range: */
                if (range_startk)
-                       max_align = ffs(range_startk) - 1;
+                       max_align = __ffs(range_startk);
                else
-                       max_align = 32;
+                       max_align = BITS_PER_LONG - 1;
 
-               align = fls(range_sizek) - 1;
+               align = __fls(range_sizek);
                if (align > max_align)
                        align = max_align;
 
index 75772ae6c65f81cbc2268120b1fdcf3bad80028f..e9fe907cd2495c9ad6a687f9b45a49c39a5ebd26 100644 (file)
@@ -361,11 +361,7 @@ static void __init print_mtrr_state(void)
        }
        pr_debug("MTRR variable ranges %sabled:\n",
                 mtrr_state.enabled & 2 ? "en" : "dis");
-       if (size_or_mask & 0xffffffffUL)
-               high_width = ffs(size_or_mask & 0xffffffffUL) - 1;
-       else
-               high_width = ffs(size_or_mask>>32) + 32 - 1;
-       high_width = (high_width - (32 - PAGE_SHIFT) + 3) / 4;
+       high_width = (__ffs64(size_or_mask) - (32 - PAGE_SHIFT) + 3) / 4;
 
        for (i = 0; i < num_var_ranges; ++i) {
                if (mtrr_state.var_ranges[i].mask_lo & (1 << 11))
index c4706cf9c011d8fd068d205ed0b669142c112400..29557aa06dda6a724add1d6be6f7744f2d801d34 100644 (file)
 
 #include "perf_event.h"
 
-#if 0
-#undef wrmsrl
-#define wrmsrl(msr, val)                                       \
-do {                                                           \
-       trace_printk("wrmsrl(%lx, %lx)\n", (unsigned long)(msr),\
-                       (unsigned long)(val));                  \
-       native_write_msr((msr), (u32)((u64)(val)),              \
-                       (u32)((u64)(val) >> 32));               \
-} while (0)
-#endif
-
 struct x86_pmu x86_pmu __read_mostly;
 
 DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
@@ -74,7 +63,7 @@ u64 x86_perf_event_update(struct perf_event *event)
        int idx = hwc->idx;
        s64 delta;
 
-       if (idx == X86_PMC_IDX_FIXED_BTS)
+       if (idx == INTEL_PMC_IDX_FIXED_BTS)
                return 0;
 
        /*
@@ -86,7 +75,7 @@ u64 x86_perf_event_update(struct perf_event *event)
         */
 again:
        prev_raw_count = local64_read(&hwc->prev_count);
-       rdmsrl(hwc->event_base, new_raw_count);
+       rdpmcl(hwc->event_base_rdpmc, new_raw_count);
 
        if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
                                        new_raw_count) != prev_raw_count)
@@ -189,7 +178,7 @@ static void release_pmc_hardware(void) {}
 
 static bool check_hw_exists(void)
 {
-       u64 val, val_new = 0;
+       u64 val, val_new = ~0;
        int i, reg, ret = 0;
 
        /*
@@ -222,8 +211,9 @@ static bool check_hw_exists(void)
         * that don't trap on the MSR access and always return 0s.
         */
        val = 0xabcdUL;
-       ret = checking_wrmsrl(x86_pmu_event_addr(0), val);
-       ret |= rdmsrl_safe(x86_pmu_event_addr(0), &val_new);
+       reg = x86_pmu_event_addr(0);
+       ret = wrmsrl_safe(reg, val);
+       ret |= rdmsrl_safe(reg, &val_new);
        if (ret || val != val_new)
                goto msr_fail;
 
@@ -240,6 +230,7 @@ bios_fail:
 
 msr_fail:
        printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n");
+       printk(KERN_ERR "Failed to access perfctr msr (MSR %x is %Lx)\n", reg, val_new);
 
        return false;
 }
@@ -388,7 +379,7 @@ int x86_pmu_hw_config(struct perf_event *event)
                int precise = 0;
 
                /* Support for constant skid */
-               if (x86_pmu.pebs_active) {
+               if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
                        precise++;
 
                        /* Support for IP fixup */
@@ -637,8 +628,8 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
        c = sched->constraints[sched->state.event];
 
        /* Prefer fixed purpose counters */
-       if (x86_pmu.num_counters_fixed) {
-               idx = X86_PMC_IDX_FIXED;
+       if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) {
+               idx = INTEL_PMC_IDX_FIXED;
                for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) {
                        if (!__test_and_set_bit(idx, sched->state.used))
                                goto done;
@@ -646,7 +637,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched)
        }
        /* Grab the first unused counter starting with idx */
        idx = sched->state.counter;
-       for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_FIXED) {
+       for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) {
                if (!__test_and_set_bit(idx, sched->state.used))
                        goto done;
        }
@@ -704,8 +695,8 @@ static bool perf_sched_next_event(struct perf_sched *sched)
 /*
  * Assign a counter for each event.
  */
-static int perf_assign_events(struct event_constraint **constraints, int n,
-                             int wmin, int wmax, int *assign)
+int perf_assign_events(struct event_constraint **constraints, int n,
+                       int wmin, int wmax, int *assign)
 {
        struct perf_sched sched;
 
@@ -824,15 +815,17 @@ static inline void x86_assign_hw_event(struct perf_event *event,
        hwc->last_cpu = smp_processor_id();
        hwc->last_tag = ++cpuc->tags[i];
 
-       if (hwc->idx == X86_PMC_IDX_FIXED_BTS) {
+       if (hwc->idx == INTEL_PMC_IDX_FIXED_BTS) {
                hwc->config_base = 0;
                hwc->event_base = 0;
-       } else if (hwc->idx >= X86_PMC_IDX_FIXED) {
+       } else if (hwc->idx >= INTEL_PMC_IDX_FIXED) {
                hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
-               hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - X86_PMC_IDX_FIXED);
+               hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - INTEL_PMC_IDX_FIXED);
+               hwc->event_base_rdpmc = (hwc->idx - INTEL_PMC_IDX_FIXED) | 1<<30;
        } else {
                hwc->config_base = x86_pmu_config_addr(hwc->idx);
                hwc->event_base  = x86_pmu_event_addr(hwc->idx);
+               hwc->event_base_rdpmc = hwc->idx;
        }
 }
 
@@ -930,7 +923,7 @@ int x86_perf_event_set_period(struct perf_event *event)
        s64 period = hwc->sample_period;
        int ret = 0, idx = hwc->idx;
 
-       if (idx == X86_PMC_IDX_FIXED_BTS)
+       if (idx == INTEL_PMC_IDX_FIXED_BTS)
                return 0;
 
        /*
@@ -1316,7 +1309,6 @@ static struct attribute_group x86_pmu_format_group = {
 static int __init init_hw_perf_events(void)
 {
        struct x86_pmu_quirk *quirk;
-       struct event_constraint *c;
        int err;
 
        pr_info("Performance Events: ");
@@ -1347,21 +1339,8 @@ static int __init init_hw_perf_events(void)
        for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
                quirk->func();
 
-       if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) {
-               WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!",
-                    x86_pmu.num_counters, X86_PMC_MAX_GENERIC);
-               x86_pmu.num_counters = X86_PMC_MAX_GENERIC;
-       }
-       x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
-
-       if (x86_pmu.num_counters_fixed > X86_PMC_MAX_FIXED) {
-               WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!",
-                    x86_pmu.num_counters_fixed, X86_PMC_MAX_FIXED);
-               x86_pmu.num_counters_fixed = X86_PMC_MAX_FIXED;
-       }
-
-       x86_pmu.intel_ctrl |=
-               ((1LL << x86_pmu.num_counters_fixed)-1) << X86_PMC_IDX_FIXED;
+       if (!x86_pmu.intel_ctrl)
+               x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
 
        perf_events_lapic_init();
        register_nmi_handler(NMI_LOCAL, perf_event_nmi_handler, 0, "PMI");
@@ -1370,22 +1349,6 @@ static int __init init_hw_perf_events(void)
                __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
                                   0, x86_pmu.num_counters, 0);
 
-       if (x86_pmu.event_constraints) {
-               /*
-                * event on fixed counter2 (REF_CYCLES) only works on this
-                * counter, so do not extend mask to generic counters
-                */
-               for_each_event_constraint(c, x86_pmu.event_constraints) {
-                       if (c->cmask != X86_RAW_EVENT_MASK
-                           || c->idxmsk64 == X86_PMC_MSK_FIXED_REF_CYCLES) {
-                               continue;
-                       }
-
-                       c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
-                       c->weight += x86_pmu.num_counters;
-               }
-       }
-
        x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
        x86_pmu_format_group.attrs = x86_pmu.format_attrs;
 
@@ -1620,8 +1583,8 @@ static int x86_pmu_event_idx(struct perf_event *event)
        if (!x86_pmu.attr_rdpmc)
                return 0;
 
-       if (x86_pmu.num_counters_fixed && idx >= X86_PMC_IDX_FIXED) {
-               idx -= X86_PMC_IDX_FIXED;
+       if (x86_pmu.num_counters_fixed && idx >= INTEL_PMC_IDX_FIXED) {
+               idx -= INTEL_PMC_IDX_FIXED;
                idx |= 1 << 30;
        }
 
@@ -1649,7 +1612,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
                              struct device_attribute *attr,
                              const char *buf, size_t count)
 {
-       unsigned long val = simple_strtoul(buf, NULL, 0);
+       unsigned long val;
+       ssize_t ret;
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret)
+               return ret;
 
        if (!!val != !!x86_pmu.attr_rdpmc) {
                x86_pmu.attr_rdpmc = !!val;
@@ -1682,13 +1650,20 @@ static void x86_pmu_flush_branch_stack(void)
                x86_pmu.flush_branch_stack();
 }
 
+void perf_check_microcode(void)
+{
+       if (x86_pmu.check_microcode)
+               x86_pmu.check_microcode();
+}
+EXPORT_SYMBOL_GPL(perf_check_microcode);
+
 static struct pmu pmu = {
        .pmu_enable             = x86_pmu_enable,
        .pmu_disable            = x86_pmu_disable,
 
-       .attr_groups    = x86_pmu_attr_groups,
+       .attr_groups            = x86_pmu_attr_groups,
 
-       .event_init     = x86_pmu_event_init,
+       .event_init             = x86_pmu_event_init,
 
        .add                    = x86_pmu_add,
        .del                    = x86_pmu_del,
@@ -1696,11 +1671,11 @@ static struct pmu pmu = {
        .stop                   = x86_pmu_stop,
        .read                   = x86_pmu_read,
 
-       .start_txn      = x86_pmu_start_txn,
-       .cancel_txn     = x86_pmu_cancel_txn,
-       .commit_txn     = x86_pmu_commit_txn,
+       .start_txn              = x86_pmu_start_txn,
+       .cancel_txn             = x86_pmu_cancel_txn,
+       .commit_txn             = x86_pmu_commit_txn,
 
-       .event_idx      = x86_pmu_event_idx,
+       .event_idx              = x86_pmu_event_idx,
        .flush_branch_stack     = x86_pmu_flush_branch_stack,
 };
 
@@ -1863,7 +1838,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
                else
                        misc |= PERF_RECORD_MISC_GUEST_KERNEL;
        } else {
-               if (user_mode(regs))
+               if (!kernel_ip(regs->ip))
                        misc |= PERF_RECORD_MISC_USER;
                else
                        misc |= PERF_RECORD_MISC_KERNEL;
index 7241e2fc3c17c87b766c35f8d412b8692436b825..a15df4be151fc924e3cf8a9b25ab18c991c0b58c 100644 (file)
 
 #include <linux/perf_event.h>
 
+#if 0
+#undef wrmsrl
+#define wrmsrl(msr, val)                                               \
+do {                                                                   \
+       unsigned int _msr = (msr);                                      \
+       u64 _val = (val);                                               \
+       trace_printk("wrmsrl(%x, %Lx)\n", (unsigned int)(_msr),         \
+                       (unsigned long long)(_val));                    \
+       native_write_msr((_msr), (u32)(_val), (u32)(_val >> 32));       \
+} while (0)
+#endif
+
 /*
  *          |   NHM/WSM    |      SNB     |
  * register -------------------------------
@@ -57,7 +69,7 @@ struct amd_nb {
 };
 
 /* The maximal number of PEBS events: */
-#define MAX_PEBS_EVENTS                4
+#define MAX_PEBS_EVENTS                8
 
 /*
  * A debug store configuration.
@@ -349,6 +361,8 @@ struct x86_pmu {
        void            (*cpu_starting)(int cpu);
        void            (*cpu_dying)(int cpu);
        void            (*cpu_dead)(int cpu);
+
+       void            (*check_microcode)(void);
        void            (*flush_branch_stack)(void);
 
        /*
@@ -360,12 +374,16 @@ struct x86_pmu {
        /*
         * Intel DebugStore bits
         */
-       int             bts, pebs;
-       int             bts_active, pebs_active;
+       int             bts             :1,
+                       bts_active      :1,
+                       pebs            :1,
+                       pebs_active     :1,
+                       pebs_broken     :1;
        int             pebs_record_size;
        void            (*drain_pebs)(struct pt_regs *regs);
        struct event_constraint *pebs_constraints;
        void            (*pebs_aliases)(struct perf_event *event);
+       int             max_pebs_events;
 
        /*
         * Intel LBR
@@ -468,6 +486,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
 
 void x86_pmu_enable_all(int added);
 
+int perf_assign_events(struct event_constraint **constraints, int n,
+                       int wmin, int wmax, int *assign);
 int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign);
 
 void x86_pmu_stop(struct perf_event *event, int flags);
index 11a4eb9131d5cbddc70ca663ab4c3eb27add8143..4528ae7b6ec4c96aaeb9822b3ea82bad59c4fc7a 100644 (file)
@@ -366,7 +366,7 @@ static void amd_pmu_cpu_starting(int cpu)
 
        cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY;
 
-       if (boot_cpu_data.x86_max_cores < 2 || boot_cpu_data.x86 == 0x15)
+       if (boot_cpu_data.x86_max_cores < 2)
                return;
 
        nb_id = amd_get_nb_id(cpu);
@@ -422,35 +422,6 @@ static struct attribute *amd_format_attr[] = {
        NULL,
 };
 
-static __initconst const struct x86_pmu amd_pmu = {
-       .name                   = "AMD",
-       .handle_irq             = x86_pmu_handle_irq,
-       .disable_all            = x86_pmu_disable_all,
-       .enable_all             = x86_pmu_enable_all,
-       .enable                 = x86_pmu_enable_event,
-       .disable                = x86_pmu_disable_event,
-       .hw_config              = amd_pmu_hw_config,
-       .schedule_events        = x86_schedule_events,
-       .eventsel               = MSR_K7_EVNTSEL0,
-       .perfctr                = MSR_K7_PERFCTR0,
-       .event_map              = amd_pmu_event_map,
-       .max_events             = ARRAY_SIZE(amd_perfmon_event_map),
-       .num_counters           = AMD64_NUM_COUNTERS,
-       .cntval_bits            = 48,
-       .cntval_mask            = (1ULL << 48) - 1,
-       .apic                   = 1,
-       /* use highest bit to detect overflow */
-       .max_period             = (1ULL << 47) - 1,
-       .get_event_constraints  = amd_get_event_constraints,
-       .put_event_constraints  = amd_put_event_constraints,
-
-       .format_attrs           = amd_format_attr,
-
-       .cpu_prepare            = amd_pmu_cpu_prepare,
-       .cpu_starting           = amd_pmu_cpu_starting,
-       .cpu_dead               = amd_pmu_cpu_dead,
-};
-
 /* AMD Family 15h */
 
 #define AMD_EVENT_TYPE_MASK    0x000000F0ULL
@@ -597,8 +568,8 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev
        }
 }
 
-static __initconst const struct x86_pmu amd_pmu_f15h = {
-       .name                   = "AMD Family 15h",
+static __initconst const struct x86_pmu amd_pmu = {
+       .name                   = "AMD",
        .handle_irq             = x86_pmu_handle_irq,
        .disable_all            = x86_pmu_disable_all,
        .enable_all             = x86_pmu_enable_all,
@@ -606,50 +577,68 @@ static __initconst const struct x86_pmu amd_pmu_f15h = {
        .disable                = x86_pmu_disable_event,
        .hw_config              = amd_pmu_hw_config,
        .schedule_events        = x86_schedule_events,
-       .eventsel               = MSR_F15H_PERF_CTL,
-       .perfctr                = MSR_F15H_PERF_CTR,
+       .eventsel               = MSR_K7_EVNTSEL0,
+       .perfctr                = MSR_K7_PERFCTR0,
        .event_map              = amd_pmu_event_map,
        .max_events             = ARRAY_SIZE(amd_perfmon_event_map),
-       .num_counters           = AMD64_NUM_COUNTERS_F15H,
+       .num_counters           = AMD64_NUM_COUNTERS,
        .cntval_bits            = 48,
        .cntval_mask            = (1ULL << 48) - 1,
        .apic                   = 1,
        /* use highest bit to detect overflow */
        .max_period             = (1ULL << 47) - 1,
-       .get_event_constraints  = amd_get_event_constraints_f15h,
-       /* nortbridge counters not yet implemented: */
-#if 0
+       .get_event_constraints  = amd_get_event_constraints,
        .put_event_constraints  = amd_put_event_constraints,
 
+       .format_attrs           = amd_format_attr,
+
        .cpu_prepare            = amd_pmu_cpu_prepare,
-       .cpu_dead               = amd_pmu_cpu_dead,
-#endif
        .cpu_starting           = amd_pmu_cpu_starting,
-       .format_attrs           = amd_format_attr,
+       .cpu_dead               = amd_pmu_cpu_dead,
 };
 
+static int setup_event_constraints(void)
+{
+       if (boot_cpu_data.x86 >= 0x15)
+               x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
+       return 0;
+}
+
+static int setup_perfctr_core(void)
+{
+       if (!cpu_has_perfctr_core) {
+               WARN(x86_pmu.get_event_constraints == amd_get_event_constraints_f15h,
+                    KERN_ERR "Odd, counter constraints enabled but no core perfctrs detected!");
+               return -ENODEV;
+       }
+
+       WARN(x86_pmu.get_event_constraints == amd_get_event_constraints,
+            KERN_ERR "hw perf events core counters need constraints handler!");
+
+       /*
+        * If core performance counter extensions exists, we must use
+        * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also
+        * x86_pmu_addr_offset().
+        */
+       x86_pmu.eventsel        = MSR_F15H_PERF_CTL;
+       x86_pmu.perfctr         = MSR_F15H_PERF_CTR;
+       x86_pmu.num_counters    = AMD64_NUM_COUNTERS_CORE;
+
+       printk(KERN_INFO "perf: AMD core performance counters detected\n");
+
+       return 0;
+}
+
 __init int amd_pmu_init(void)
 {
        /* Performance-monitoring supported from K7 and later: */
        if (boot_cpu_data.x86 < 6)
                return -ENODEV;
 
-       /*
-        * If core performance counter extensions exists, it must be
-        * family 15h, otherwise fail. See x86_pmu_addr_offset().
-        */
-       switch (boot_cpu_data.x86) {
-       case 0x15:
-               if (!cpu_has_perfctr_core)
-                       return -ENODEV;
-               x86_pmu = amd_pmu_f15h;
-               break;
-       default:
-               if (cpu_has_perfctr_core)
-                       return -ENODEV;
-               x86_pmu = amd_pmu;
-               break;
-       }
+       x86_pmu = amd_pmu;
+
+       setup_event_constraints();
+       setup_perfctr_core();
 
        /* Events are common for all AMDs */
        memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
index 187c294bc6583424e8613df62a883740ab8fca1a..7a8b9d0abcaa33c754481cf38c3f26c366f701c9 100644 (file)
@@ -5,6 +5,8 @@
  * among events on a single PMU.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/init.h>
  */
 static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
 {
-  [PERF_COUNT_HW_CPU_CYCLES]           = 0x003c,
-  [PERF_COUNT_HW_INSTRUCTIONS]         = 0x00c0,
-  [PERF_COUNT_HW_CACHE_REFERENCES]     = 0x4f2e,
-  [PERF_COUNT_HW_CACHE_MISSES]         = 0x412e,
-  [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]  = 0x00c4,
-  [PERF_COUNT_HW_BRANCH_MISSES]                = 0x00c5,
-  [PERF_COUNT_HW_BUS_CYCLES]           = 0x013c,
-  [PERF_COUNT_HW_REF_CPU_CYCLES]       = 0x0300, /* pseudo-encoding */
+       [PERF_COUNT_HW_CPU_CYCLES]              = 0x003c,
+       [PERF_COUNT_HW_INSTRUCTIONS]            = 0x00c0,
+       [PERF_COUNT_HW_CACHE_REFERENCES]        = 0x4f2e,
+       [PERF_COUNT_HW_CACHE_MISSES]            = 0x412e,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS]     = 0x00c4,
+       [PERF_COUNT_HW_BRANCH_MISSES]           = 0x00c5,
+       [PERF_COUNT_HW_BUS_CYCLES]              = 0x013c,
+       [PERF_COUNT_HW_REF_CPU_CYCLES]          = 0x0300, /* pseudo-encoding */
 };
 
 static struct event_constraint intel_core_event_constraints[] __read_mostly =
@@ -747,7 +749,7 @@ static void intel_pmu_disable_all(void)
 
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
 
-       if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask))
+       if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask))
                intel_pmu_disable_bts();
 
        intel_pmu_pebs_disable_all();
@@ -763,9 +765,9 @@ static void intel_pmu_enable_all(int added)
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL,
                        x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask);
 
-       if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) {
+       if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask)) {
                struct perf_event *event =
-                       cpuc->events[X86_PMC_IDX_FIXED_BTS];
+                       cpuc->events[INTEL_PMC_IDX_FIXED_BTS];
 
                if (WARN_ON_ONCE(!event))
                        return;
@@ -871,7 +873,7 @@ static inline void intel_pmu_ack_status(u64 ack)
 
 static void intel_pmu_disable_fixed(struct hw_perf_event *hwc)
 {
-       int idx = hwc->idx - X86_PMC_IDX_FIXED;
+       int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
        u64 ctrl_val, mask;
 
        mask = 0xfULL << (idx * 4);
@@ -886,7 +888,7 @@ static void intel_pmu_disable_event(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
-       if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) {
+       if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) {
                intel_pmu_disable_bts();
                intel_pmu_drain_bts_buffer();
                return;
@@ -915,7 +917,7 @@ static void intel_pmu_disable_event(struct perf_event *event)
 
 static void intel_pmu_enable_fixed(struct hw_perf_event *hwc)
 {
-       int idx = hwc->idx - X86_PMC_IDX_FIXED;
+       int idx = hwc->idx - INTEL_PMC_IDX_FIXED;
        u64 ctrl_val, bits, mask;
 
        /*
@@ -949,7 +951,7 @@ static void intel_pmu_enable_event(struct perf_event *event)
        struct hw_perf_event *hwc = &event->hw;
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
-       if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) {
+       if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) {
                if (!__this_cpu_read(cpu_hw_events.enabled))
                        return;
 
@@ -1000,14 +1002,14 @@ static void intel_pmu_reset(void)
 
        local_irq_save(flags);
 
-       printk("clearing PMU state on CPU#%d\n", smp_processor_id());
+       pr_info("clearing PMU state on CPU#%d\n", smp_processor_id());
 
        for (idx = 0; idx < x86_pmu.num_counters; idx++) {
-               checking_wrmsrl(x86_pmu_config_addr(idx), 0ull);
-               checking_wrmsrl(x86_pmu_event_addr(idx),  0ull);
+               wrmsrl_safe(x86_pmu_config_addr(idx), 0ull);
+               wrmsrl_safe(x86_pmu_event_addr(idx),  0ull);
        }
        for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++)
-               checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
+               wrmsrl_safe(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull);
 
        if (ds)
                ds->bts_index = ds->bts_buffer_base;
@@ -1707,16 +1709,61 @@ static __init void intel_clovertown_quirk(void)
         * But taken together it might just make sense to not enable PEBS on
         * these chips.
         */
-       printk(KERN_WARNING "PEBS disabled due to CPU errata.\n");
+       pr_warn("PEBS disabled due to CPU errata\n");
        x86_pmu.pebs = 0;
        x86_pmu.pebs_constraints = NULL;
 }
 
+static int intel_snb_pebs_broken(int cpu)
+{
+       u32 rev = UINT_MAX; /* default to broken for unknown models */
+
+       switch (cpu_data(cpu).x86_model) {
+       case 42: /* SNB */
+               rev = 0x28;
+               break;
+
+       case 45: /* SNB-EP */
+               switch (cpu_data(cpu).x86_mask) {
+               case 6: rev = 0x618; break;
+               case 7: rev = 0x70c; break;
+               }
+       }
+
+       return (cpu_data(cpu).microcode < rev);
+}
+
+static void intel_snb_check_microcode(void)
+{
+       int pebs_broken = 0;
+       int cpu;
+
+       get_online_cpus();
+       for_each_online_cpu(cpu) {
+               if ((pebs_broken = intel_snb_pebs_broken(cpu)))
+                       break;
+       }
+       put_online_cpus();
+
+       if (pebs_broken == x86_pmu.pebs_broken)
+               return;
+
+       /*
+        * Serialized by the microcode lock..
+        */
+       if (x86_pmu.pebs_broken) {
+               pr_info("PEBS enabled due to microcode update\n");
+               x86_pmu.pebs_broken = 0;
+       } else {
+               pr_info("PEBS disabled due to CPU errata, please upgrade microcode\n");
+               x86_pmu.pebs_broken = 1;
+       }
+}
+
 static __init void intel_sandybridge_quirk(void)
 {
-       printk(KERN_WARNING "PEBS disabled due to CPU errata.\n");
-       x86_pmu.pebs = 0;
-       x86_pmu.pebs_constraints = NULL;
+       x86_pmu.check_microcode = intel_snb_check_microcode;
+       intel_snb_check_microcode();
 }
 
 static const struct { int id; char *name; } intel_arch_events_map[] __initconst = {
@@ -1736,8 +1783,8 @@ static __init void intel_arch_events_quirk(void)
        /* disable event that reported as not presend by cpuid */
        for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_arch_events_map)) {
                intel_perfmon_event_map[intel_arch_events_map[bit].id] = 0;
-               printk(KERN_WARNING "CPUID marked event: \'%s\' unavailable\n",
-                               intel_arch_events_map[bit].name);
+               pr_warn("CPUID marked event: \'%s\' unavailable\n",
+                       intel_arch_events_map[bit].name);
        }
 }
 
@@ -1756,7 +1803,7 @@ static __init void intel_nehalem_quirk(void)
                intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89;
                ebx.split.no_branch_misses_retired = 0;
                x86_pmu.events_maskl = ebx.full;
-               printk(KERN_INFO "CPU erratum AAJ80 worked around\n");
+               pr_info("CPU erratum AAJ80 worked around\n");
        }
 }
 
@@ -1765,6 +1812,7 @@ __init int intel_pmu_init(void)
        union cpuid10_edx edx;
        union cpuid10_eax eax;
        union cpuid10_ebx ebx;
+       struct event_constraint *c;
        unsigned int unused;
        int version;
 
@@ -1800,6 +1848,8 @@ __init int intel_pmu_init(void)
        x86_pmu.events_maskl            = ebx.full;
        x86_pmu.events_mask_len         = eax.split.mask_length;
 
+       x86_pmu.max_pebs_events         = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters);
+
        /*
         * Quirk: v2 perfmon does not report fixed-purpose events, so
         * assume at least 3 events:
@@ -1951,5 +2001,37 @@ __init int intel_pmu_init(void)
                }
        }
 
+       if (x86_pmu.num_counters > INTEL_PMC_MAX_GENERIC) {
+               WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!",
+                    x86_pmu.num_counters, INTEL_PMC_MAX_GENERIC);
+               x86_pmu.num_counters = INTEL_PMC_MAX_GENERIC;
+       }
+       x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
+
+       if (x86_pmu.num_counters_fixed > INTEL_PMC_MAX_FIXED) {
+               WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!",
+                    x86_pmu.num_counters_fixed, INTEL_PMC_MAX_FIXED);
+               x86_pmu.num_counters_fixed = INTEL_PMC_MAX_FIXED;
+       }
+
+       x86_pmu.intel_ctrl |=
+               ((1LL << x86_pmu.num_counters_fixed)-1) << INTEL_PMC_IDX_FIXED;
+
+       if (x86_pmu.event_constraints) {
+               /*
+                * event on fixed counter2 (REF_CYCLES) only works on this
+                * counter, so do not extend mask to generic counters
+                */
+               for_each_event_constraint(c, x86_pmu.event_constraints) {
+                       if (c->cmask != X86_RAW_EVENT_MASK
+                           || c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) {
+                               continue;
+                       }
+
+                       c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1;
+                       c->weight += x86_pmu.num_counters;
+               }
+       }
+
        return 0;
 }
index 35e2192df9f4ae078ae8ecff742f72f30881816b..629ae0b7ad901c88706716966b1fd71415debe19 100644 (file)
@@ -248,7 +248,7 @@ void reserve_ds_buffers(void)
  */
 
 struct event_constraint bts_constraint =
-       EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0);
+       EVENT_CONSTRAINT(0, 1ULL << INTEL_PMC_IDX_FIXED_BTS, 0);
 
 void intel_pmu_enable_bts(u64 config)
 {
@@ -295,7 +295,7 @@ int intel_pmu_drain_bts_buffer(void)
                u64     to;
                u64     flags;
        };
-       struct perf_event *event = cpuc->events[X86_PMC_IDX_FIXED_BTS];
+       struct perf_event *event = cpuc->events[INTEL_PMC_IDX_FIXED_BTS];
        struct bts_record *at, *top;
        struct perf_output_handle handle;
        struct perf_event_header header;
@@ -620,7 +620,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
         * Should not happen, we program the threshold at 1 and do not
         * set a reset value.
         */
-       WARN_ON_ONCE(n > 1);
+       WARN_ONCE(n > 1, "bad leftover pebs %d\n", n);
        at += n - 1;
 
        __intel_pmu_pebs_event(event, iregs, at);
@@ -651,10 +651,10 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
         * Should not happen, we program the threshold at 1 and do not
         * set a reset value.
         */
-       WARN_ON_ONCE(n > MAX_PEBS_EVENTS);
+       WARN_ONCE(n > x86_pmu.max_pebs_events, "Unexpected number of pebs records %d\n", n);
 
        for ( ; at < top; at++) {
-               for_each_set_bit(bit, (unsigned long *)&at->status, MAX_PEBS_EVENTS) {
+               for_each_set_bit(bit, (unsigned long *)&at->status, x86_pmu.max_pebs_events) {
                        event = cpuc->events[bit];
                        if (!test_bit(bit, cpuc->active_mask))
                                continue;
@@ -670,7 +670,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
                        break;
                }
 
-               if (!event || bit >= MAX_PEBS_EVENTS)
+               if (!event || bit >= x86_pmu.max_pebs_events)
                        continue;
 
                __intel_pmu_pebs_event(event, iregs, at);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
new file mode 100644 (file)
index 0000000..19faffc
--- /dev/null
@@ -0,0 +1,1850 @@
+#include "perf_event_intel_uncore.h"
+
+static struct intel_uncore_type *empty_uncore[] = { NULL, };
+static struct intel_uncore_type **msr_uncores = empty_uncore;
+static struct intel_uncore_type **pci_uncores = empty_uncore;
+/* pci bus to socket mapping */
+static int pcibus_to_physid[256] = { [0 ... 255] = -1, };
+
+static DEFINE_RAW_SPINLOCK(uncore_box_lock);
+
+/* mask of cpus that collect uncore events */
+static cpumask_t uncore_cpu_mask;
+
+/* constraint for the fixed counter */
+static struct event_constraint constraint_fixed =
+       EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
+static struct event_constraint constraint_empty =
+       EVENT_CONSTRAINT(0, 0, 0);
+
+DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
+DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
+DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
+DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
+DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
+DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
+DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
+DEFINE_UNCORE_FORMAT_ATTR(filter_brand0, filter_brand0, "config1:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(filter_brand1, filter_brand1, "config1:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(filter_brand2, filter_brand2, "config1:16-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_brand3, filter_brand3, "config1:24-31");
+
+/* Sandy Bridge-EP uncore support */
+static struct intel_uncore_type snbep_uncore_cbox;
+static struct intel_uncore_type snbep_uncore_pcu;
+
+static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
+       u32 config;
+
+       pci_read_config_dword(pdev, box_ctl, &config);
+       config |= SNBEP_PMON_BOX_CTL_FRZ;
+       pci_write_config_dword(pdev, box_ctl, config);
+}
+
+static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       int box_ctl = uncore_pci_box_ctl(box);
+       u32 config;
+
+       pci_read_config_dword(pdev, box_ctl, &config);
+       config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+       pci_write_config_dword(pdev, box_ctl, config);
+}
+
+static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config |
+                               SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+
+       pci_write_config_dword(pdev, hwc->config_base, hwc->config);
+}
+
+static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count;
+
+       pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count);
+       pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1);
+       return count;
+}
+
+static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL,
+                               SNBEP_PMON_BOX_CTL_INT);
+}
+
+static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       u64 config;
+       unsigned msr;
+
+       msr = uncore_msr_box_ctl(box);
+       if (msr) {
+               rdmsrl(msr, config);
+               config |= SNBEP_PMON_BOX_CTL_FRZ;
+               wrmsrl(msr, config);
+               return;
+       }
+}
+
+static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       u64 config;
+       unsigned msr;
+
+       msr = uncore_msr_box_ctl(box);
+       if (msr) {
+               rdmsrl(msr, config);
+               config &= ~SNBEP_PMON_BOX_CTL_FRZ;
+               wrmsrl(msr, config);
+               return;
+       }
+}
+
+static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (reg1->idx != EXTRA_REG_NONE)
+               wrmsrl(reg1->reg, reg1->config);
+
+       wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       wrmsrl(hwc->config_base, hwc->config);
+}
+
+static u64 snbep_uncore_msr_read_counter(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       u64 count;
+
+       rdmsrl(hwc->event_base, count);
+       return count;
+}
+
+static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       unsigned msr = uncore_msr_box_ctl(box);
+       if (msr)
+               wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
+}
+
+static struct event_constraint *
+snbep_uncore_get_constraint(struct intel_uncore_box *box,
+                           struct perf_event *event)
+{
+       struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+       unsigned long flags;
+       bool ok = false;
+
+       if (reg1->idx == EXTRA_REG_NONE || (box->phys_id >= 0 && reg1->alloc))
+               return NULL;
+
+       er = &box->shared_regs[reg1->idx];
+       raw_spin_lock_irqsave(&er->lock, flags);
+       if (!atomic_read(&er->ref) || er->config1 == reg1->config) {
+               atomic_inc(&er->ref);
+               er->config1 = reg1->config;
+               ok = true;
+       }
+       raw_spin_unlock_irqrestore(&er->lock, flags);
+
+       if (ok) {
+               if (box->phys_id >= 0)
+                       reg1->alloc = 1;
+               return NULL;
+       }
+       return &constraint_empty;
+}
+
+static void snbep_uncore_put_constraint(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct intel_uncore_extra_reg *er;
+       struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+
+       if (box->phys_id < 0 || !reg1->alloc)
+               return;
+
+       er = &box->shared_regs[reg1->idx];
+       atomic_dec(&er->ref);
+       reg1->alloc = 0;
+}
+
+static int snbep_uncore_hw_config(struct intel_uncore_box *box,
+                                 struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+       if (box->pmu->type == &snbep_uncore_cbox) {
+               reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+                       SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+               reg1->config = event->attr.config1 &
+                       SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK;
+       } else if (box->pmu->type == &snbep_uncore_pcu) {
+               reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
+               reg1->config = event->attr.config1 &
+                       SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK;
+       } else {
+               return 0;
+       }
+       reg1->idx = 0;
+       return 0;
+}
+
+static struct attribute *snbep_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_ubox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_cbox_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_tid_en.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh8.attr,
+       &format_attr_filter_tid.attr,
+       &format_attr_filter_nid.attr,
+       &format_attr_filter_state.attr,
+       &format_attr_filter_opc.attr,
+       NULL,
+};
+
+static struct attribute *snbep_uncore_pcu_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_occ_sel.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_thresh5.attr,
+       &format_attr_occ_invert.attr,
+       &format_attr_occ_edge.attr,
+       &format_attr_filter_brand0.attr,
+       &format_attr_filter_brand1.attr,
+       &format_attr_filter_brand2.attr,
+       &format_attr_filter_brand3.attr,
+       NULL,
+};
+
+static struct uncore_event_desc snbep_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,      "event=0xff,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_read,  "event=0x04,umask=0x03"),
+       INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+       { /* end: all zeroes */ },
+};
+
+static struct uncore_event_desc snbep_uncore_qpi_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,       "event=0x14"),
+       INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"),
+       INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x02,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x03,umask=0x04"),
+       { /* end: all zeroes */ },
+};
+
+static struct attribute_group snbep_uncore_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_ubox_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_cbox_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group snbep_uncore_pcu_format_group = {
+       .name = "format",
+       .attrs = snbep_uncore_pcu_formats_attr,
+};
+
+static struct intel_uncore_ops snbep_uncore_msr_ops = {
+       .init_box       = snbep_uncore_msr_init_box,
+       .disable_box    = snbep_uncore_msr_disable_box,
+       .enable_box     = snbep_uncore_msr_enable_box,
+       .disable_event  = snbep_uncore_msr_disable_event,
+       .enable_event   = snbep_uncore_msr_enable_event,
+       .read_counter   = snbep_uncore_msr_read_counter,
+       .get_constraint = snbep_uncore_get_constraint,
+       .put_constraint = snbep_uncore_put_constraint,
+       .hw_config      = snbep_uncore_hw_config,
+};
+
+static struct intel_uncore_ops snbep_uncore_pci_ops = {
+       .init_box       = snbep_uncore_pci_init_box,
+       .disable_box    = snbep_uncore_pci_disable_box,
+       .enable_box     = snbep_uncore_pci_enable_box,
+       .disable_event  = snbep_uncore_pci_disable_event,
+       .enable_event   = snbep_uncore_pci_enable_event,
+       .read_counter   = snbep_uncore_pci_read_counter,
+};
+
+static struct event_constraint snbep_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x01, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x02, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x04, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x05, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x07, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x1b, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1c, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1d, 0xc),
+       UNCORE_EVENT_CONSTRAINT(0x1e, 0xc),
+       EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x35, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x3b, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r2pcie_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x30, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+       UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snbep_uncore_ubox = {
+       .name           = "ubox",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNBEP_U_MSR_PMON_CTR0,
+       .event_ctl      = SNBEP_U_MSR_PMON_CTL0,
+       .event_mask     = SNBEP_U_MSR_PMON_RAW_EVENT_MASK,
+       .fixed_ctr      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
+       .fixed_ctl      = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
+       .ops            = &snbep_uncore_msr_ops,
+       .format_group   = &snbep_uncore_ubox_format_group,
+};
+
+static struct intel_uncore_type snbep_uncore_cbox = {
+       .name                   = "cbox",
+       .num_counters           = 4,
+       .num_boxes              = 8,
+       .perf_ctr_bits          = 44,
+       .event_ctl              = SNBEP_C0_MSR_PMON_CTL0,
+       .perf_ctr               = SNBEP_C0_MSR_PMON_CTR0,
+       .event_mask             = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_C0_MSR_PMON_BOX_CTL,
+       .msr_offset             = SNBEP_CBO_MSR_OFFSET,
+       .num_shared_regs        = 1,
+       .constraints            = snbep_uncore_cbox_constraints,
+       .ops                    = &snbep_uncore_msr_ops,
+       .format_group           = &snbep_uncore_cbox_format_group,
+};
+
+static struct intel_uncore_type snbep_uncore_pcu = {
+       .name                   = "pcu",
+       .num_counters           = 4,
+       .num_boxes              = 1,
+       .perf_ctr_bits          = 48,
+       .perf_ctr               = SNBEP_PCU_MSR_PMON_CTR0,
+       .event_ctl              = SNBEP_PCU_MSR_PMON_CTL0,
+       .event_mask             = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
+       .box_ctl                = SNBEP_PCU_MSR_PMON_BOX_CTL,
+       .num_shared_regs        = 1,
+       .ops                    = &snbep_uncore_msr_ops,
+       .format_group           = &snbep_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *snbep_msr_uncores[] = {
+       &snbep_uncore_ubox,
+       &snbep_uncore_cbox,
+       &snbep_uncore_pcu,
+       NULL,
+};
+
+#define SNBEP_UNCORE_PCI_COMMON_INIT()                         \
+       .perf_ctr       = SNBEP_PCI_PMON_CTR0,                  \
+       .event_ctl      = SNBEP_PCI_PMON_CTL0,                  \
+       .event_mask     = SNBEP_PMON_RAW_EVENT_MASK,            \
+       .box_ctl        = SNBEP_PCI_PMON_BOX_CTL,               \
+       .ops            = &snbep_uncore_pci_ops,                \
+       .format_group   = &snbep_uncore_format_group
+
+static struct intel_uncore_type snbep_uncore_ha = {
+       .name           = "ha",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 4,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .fixed_ctr      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+       .fixed_ctl      = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+       .event_descs    = snbep_uncore_imc_events,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_qpi = {
+       .name           = "qpi",
+       .num_counters   = 4,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 48,
+       .event_descs    = snbep_uncore_qpi_events,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+
+static struct intel_uncore_type snbep_uncore_r2pcie = {
+       .name           = "r2pcie",
+       .num_counters   = 4,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r2pcie_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type snbep_uncore_r3qpi = {
+       .name           = "r3qpi",
+       .num_counters   = 3,
+       .num_boxes      = 2,
+       .perf_ctr_bits  = 44,
+       .constraints    = snbep_uncore_r3qpi_constraints,
+       SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type *snbep_pci_uncores[] = {
+       &snbep_uncore_ha,
+       &snbep_uncore_imc,
+       &snbep_uncore_qpi,
+       &snbep_uncore_r2pcie,
+       &snbep_uncore_r3qpi,
+       NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = {
+       { /* Home Agent */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
+               .driver_data = (unsigned long)&snbep_uncore_ha,
+       },
+       { /* MC Channel 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
+               .driver_data = (unsigned long)&snbep_uncore_imc,
+       },
+       { /* MC Channel 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
+               .driver_data = (unsigned long)&snbep_uncore_imc,
+       },
+       { /* MC Channel 2 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
+               .driver_data = (unsigned long)&snbep_uncore_imc,
+       },
+       { /* MC Channel 3 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
+               .driver_data = (unsigned long)&snbep_uncore_imc,
+       },
+       { /* QPI Port 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
+               .driver_data = (unsigned long)&snbep_uncore_qpi,
+       },
+       { /* QPI Port 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
+               .driver_data = (unsigned long)&snbep_uncore_qpi,
+       },
+       { /* P2PCIe */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
+               .driver_data = (unsigned long)&snbep_uncore_r2pcie,
+       },
+       { /* R3QPI Link 0 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
+               .driver_data = (unsigned long)&snbep_uncore_r3qpi,
+       },
+       { /* R3QPI Link 1 */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
+               .driver_data = (unsigned long)&snbep_uncore_r3qpi,
+       },
+       { /* end: all zeroes */ }
+};
+
+static struct pci_driver snbep_uncore_pci_driver = {
+       .name           = "snbep_uncore",
+       .id_table       = snbep_uncore_pci_ids,
+};
+
+/*
+ * build pci bus to socket mapping
+ */
+static void snbep_pci2phy_map_init(void)
+{
+       struct pci_dev *ubox_dev = NULL;
+       int i, bus, nodeid;
+       u32 config;
+
+       while (1) {
+               /* find the UBOX device */
+               ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                       PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX,
+                                       ubox_dev);
+               if (!ubox_dev)
+                       break;
+               bus = ubox_dev->bus->number;
+               /* get the Node ID of the local register */
+               pci_read_config_dword(ubox_dev, 0x40, &config);
+               nodeid = config;
+               /* get the Node ID mapping */
+               pci_read_config_dword(ubox_dev, 0x54, &config);
+               /*
+                * every three bits in the Node ID mapping register maps
+                * to a particular node.
+                */
+               for (i = 0; i < 8; i++) {
+                       if (nodeid == ((config >> (3 * i)) & 0x7)) {
+                               pcibus_to_physid[bus] = i;
+                               break;
+                       }
+               }
+       };
+       return;
+}
+/* end of Sandy Bridge-EP uncore support */
+
+
+/* Sandy Bridge uncore support */
+static void snb_uncore_msr_enable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, SNB_UNC_CTL_EN);
+}
+
+static void snb_uncore_msr_disable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       wrmsrl(event->hw.config_base, 0);
+}
+
+static u64 snb_uncore_msr_read_counter(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       u64 count;
+       rdmsrl(event->hw.event_base, count);
+       return count;
+}
+
+static void snb_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+       if (box->pmu->pmu_idx == 0) {
+               wrmsrl(SNB_UNC_PERF_GLOBAL_CTL,
+                       SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL);
+       }
+}
+
+static struct attribute *snb_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask5.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_format_group = {
+       .name = "format",
+       .attrs = snb_uncore_formats_attr,
+};
+
+static struct intel_uncore_ops snb_uncore_msr_ops = {
+       .init_box       = snb_uncore_msr_init_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = snb_uncore_msr_enable_event,
+       .read_counter   = snb_uncore_msr_read_counter,
+};
+
+static struct event_constraint snb_uncore_cbox_constraints[] = {
+       UNCORE_EVENT_CONSTRAINT(0x80, 0x1),
+       UNCORE_EVENT_CONSTRAINT(0x83, 0x1),
+       EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type snb_uncore_cbox = {
+       .name           = "cbox",
+       .num_counters   = 2,
+       .num_boxes      = 4,
+       .perf_ctr_bits  = 44,
+       .fixed_ctr_bits = 48,
+       .perf_ctr       = SNB_UNC_CBO_0_PER_CTR0,
+       .event_ctl      = SNB_UNC_CBO_0_PERFEVTSEL0,
+       .fixed_ctr      = SNB_UNC_FIXED_CTR,
+       .fixed_ctl      = SNB_UNC_FIXED_CTR_CTRL,
+       .single_fixed   = 1,
+       .event_mask     = SNB_UNC_RAW_EVENT_MASK,
+       .msr_offset     = SNB_UNC_CBO_MSR_OFFSET,
+       .constraints    = snb_uncore_cbox_constraints,
+       .ops            = &snb_uncore_msr_ops,
+       .format_group   = &snb_uncore_format_group,
+};
+
+static struct intel_uncore_type *snb_msr_uncores[] = {
+       &snb_uncore_cbox,
+       NULL,
+};
+/* end of Sandy Bridge uncore support */
+
+/* Nehalem uncore support */
+static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0);
+}
+
+static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box)
+{
+       wrmsrl(NHM_UNC_PERF_GLOBAL_CTL,
+               NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC);
+}
+
+static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx < UNCORE_PMC_IDX_FIXED)
+               wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN);
+       else
+               wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN);
+}
+
+static struct attribute *nhm_uncore_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       &format_attr_edge.attr,
+       &format_attr_inv.attr,
+       &format_attr_cmask8.attr,
+       NULL,
+};
+
+static struct attribute_group nhm_uncore_format_group = {
+       .name = "format",
+       .attrs = nhm_uncore_formats_attr,
+};
+
+static struct uncore_event_desc nhm_uncore_events[] = {
+       INTEL_UNCORE_EVENT_DESC(clockticks,                "event=0xff,umask=0x00"),
+       INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,       "event=0x2f,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any,      "event=0x2c,umask=0x0f"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads,     "event=0x20,umask=0x01"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes,    "event=0x20,umask=0x02"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads,  "event=0x20,umask=0x04"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads,   "event=0x20,umask=0x10"),
+       INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes,  "event=0x20,umask=0x20"),
+       { /* end: all zeroes */ },
+};
+
+static struct intel_uncore_ops nhm_uncore_msr_ops = {
+       .disable_box    = nhm_uncore_msr_disable_box,
+       .enable_box     = nhm_uncore_msr_enable_box,
+       .disable_event  = snb_uncore_msr_disable_event,
+       .enable_event   = nhm_uncore_msr_enable_event,
+       .read_counter   = snb_uncore_msr_read_counter,
+};
+
+static struct intel_uncore_type nhm_uncore = {
+       .name           = "",
+       .num_counters   = 8,
+       .num_boxes      = 1,
+       .perf_ctr_bits  = 48,
+       .fixed_ctr_bits = 48,
+       .event_ctl      = NHM_UNC_PERFEVTSEL0,
+       .perf_ctr       = NHM_UNC_UNCORE_PMC0,
+       .fixed_ctr      = NHM_UNC_FIXED_CTR,
+       .fixed_ctl      = NHM_UNC_FIXED_CTR_CTRL,
+       .event_mask     = NHM_UNC_RAW_EVENT_MASK,
+       .event_descs    = nhm_uncore_events,
+       .ops            = &nhm_uncore_msr_ops,
+       .format_group   = &nhm_uncore_format_group,
+};
+
+static struct intel_uncore_type *nhm_msr_uncores[] = {
+       &nhm_uncore,
+       NULL,
+};
+/* end of Nehalem uncore support */
+
+static void uncore_assign_hw_event(struct intel_uncore_box *box,
+                               struct perf_event *event, int idx)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       hwc->idx = idx;
+       hwc->last_tag = ++box->tags[idx];
+
+       if (hwc->idx == UNCORE_PMC_IDX_FIXED) {
+               hwc->event_base = uncore_fixed_ctr(box);
+               hwc->config_base = uncore_fixed_ctl(box);
+               return;
+       }
+
+       hwc->config_base = uncore_event_ctl(box, hwc->idx);
+       hwc->event_base  = uncore_perf_ctr(box, hwc->idx);
+}
+
+static void uncore_perf_event_update(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       u64 prev_count, new_count, delta;
+       int shift;
+
+       if (event->hw.idx >= UNCORE_PMC_IDX_FIXED)
+               shift = 64 - uncore_fixed_ctr_bits(box);
+       else
+               shift = 64 - uncore_perf_ctr_bits(box);
+
+       /* the hrtimer might modify the previous event value */
+again:
+       prev_count = local64_read(&event->hw.prev_count);
+       new_count = uncore_read_counter(box, event);
+       if (local64_xchg(&event->hw.prev_count, new_count) != prev_count)
+               goto again;
+
+       delta = (new_count << shift) - (prev_count << shift);
+       delta >>= shift;
+
+       local64_add(delta, &event->count);
+}
+
+/*
+ * The overflow interrupt is unavailable for SandyBridge-EP, is broken
+ * for SandyBridge. So we use hrtimer to periodically poll the counter
+ * to avoid overflow.
+ */
+static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
+{
+       struct intel_uncore_box *box;
+       unsigned long flags;
+       int bit;
+
+       box = container_of(hrtimer, struct intel_uncore_box, hrtimer);
+       if (!box->n_active || box->cpu != smp_processor_id())
+               return HRTIMER_NORESTART;
+       /*
+        * disable local interrupt to prevent uncore_pmu_event_start/stop
+        * to interrupt the update process
+        */
+       local_irq_save(flags);
+
+       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));
+       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,
+                       HRTIMER_MODE_REL_PINNED, 0);
+}
+
+static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box)
+{
+       hrtimer_cancel(&box->hrtimer);
+}
+
+static void uncore_pmu_init_hrtimer(struct intel_uncore_box *box)
+{
+       hrtimer_init(&box->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       box->hrtimer.function = uncore_pmu_hrtimer;
+}
+
+struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
+                                         int cpu)
+{
+       struct intel_uncore_box *box;
+       int i, size;
+
+       size = sizeof(*box) + type->num_shared_regs *
+               sizeof(struct intel_uncore_extra_reg);
+
+       box = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO, cpu_to_node(cpu));
+       if (!box)
+               return NULL;
+
+       for (i = 0; i < type->num_shared_regs; i++)
+               raw_spin_lock_init(&box->shared_regs[i].lock);
+
+       uncore_pmu_init_hrtimer(box);
+       atomic_set(&box->refcnt, 1);
+       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)
+{
+       static 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_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_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 int uncore_collect_events(struct intel_uncore_box *box,
+                               struct perf_event *leader, bool dogrp)
+{
+       struct perf_event *event;
+       int n, max_count;
+
+       max_count = box->pmu->type->num_counters;
+       if (box->pmu->type->fixed_ctl)
+               max_count++;
+
+       if (box->n_events >= max_count)
+               return -EINVAL;
+
+       n = box->n_events;
+       box->event_list[n] = leader;
+       n++;
+       if (!dogrp)
+               return n;
+
+       list_for_each_entry(event, &leader->sibling_list, group_entry) {
+               if (event->state <= PERF_EVENT_STATE_OFF)
+                       continue;
+
+               if (n >= max_count)
+                       return -EINVAL;
+
+               box->event_list[n] = event;
+               n++;
+       }
+       return n;
+}
+
+static struct event_constraint *
+uncore_get_event_constraint(struct intel_uncore_box *box,
+                           struct perf_event *event)
+{
+       struct intel_uncore_type *type = box->pmu->type;
+       struct event_constraint *c;
+
+       if (type->ops->get_constraint) {
+               c = type->ops->get_constraint(box, event);
+               if (c)
+                       return c;
+       }
+
+       if (event->hw.config == ~0ULL)
+               return &constraint_fixed;
+
+       if (type->constraints) {
+               for_each_event_constraint(c, type->constraints) {
+                       if ((event->hw.config & c->cmask) == c->code)
+                               return c;
+               }
+       }
+
+       return &type->unconstrainted;
+}
+
+static void uncore_put_event_constraint(struct intel_uncore_box *box,
+                                       struct perf_event *event)
+{
+       if (box->pmu->type->ops->put_constraint)
+               box->pmu->type->ops->put_constraint(box, event);
+}
+
+static int uncore_assign_events(struct intel_uncore_box *box,
+                               int assign[], int n)
+{
+       unsigned long used_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
+       struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX];
+       int i, wmin, wmax, ret = 0;
+       struct hw_perf_event *hwc;
+
+       bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX);
+
+       for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) {
+               c = uncore_get_event_constraint(box, box->event_list[i]);
+               constraints[i] = c;
+               wmin = min(wmin, c->weight);
+               wmax = max(wmax, c->weight);
+       }
+
+       /* fastpath, try to reuse previous register */
+       for (i = 0; i < n; i++) {
+               hwc = &box->event_list[i]->hw;
+               c = constraints[i];
+
+               /* never assigned */
+               if (hwc->idx == -1)
+                       break;
+
+               /* constraint still honored */
+               if (!test_bit(hwc->idx, c->idxmsk))
+                       break;
+
+               /* not already used */
+               if (test_bit(hwc->idx, used_mask))
+                       break;
+
+               __set_bit(hwc->idx, used_mask);
+               if (assign)
+                       assign[i] = hwc->idx;
+       }
+       /* slow path */
+       if (i != n)
+               ret = perf_assign_events(constraints, n, wmin, wmax, assign);
+
+       if (!assign || ret) {
+               for (i = 0; i < n; i++)
+                       uncore_put_event_constraint(box, box->event_list[i]);
+       }
+       return ret ? -EINVAL : 0;
+}
+
+static void uncore_pmu_event_start(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       int idx = event->hw.idx;
+
+       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+               return;
+
+       if (WARN_ON_ONCE(idx == -1 || idx >= UNCORE_PMC_IDX_MAX))
+               return;
+
+       event->hw.state = 0;
+       box->events[idx] = event;
+       box->n_active++;
+       __set_bit(idx, box->active_mask);
+
+       local64_set(&event->hw.prev_count, uncore_read_counter(box, event));
+       uncore_enable_event(box, event);
+
+       if (box->n_active == 1) {
+               uncore_enable_box(box);
+               uncore_pmu_start_hrtimer(box);
+       }
+}
+
+static void uncore_pmu_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 (__test_and_clear_bit(hwc->idx, box->active_mask)) {
+               uncore_disable_event(box, event);
+               box->n_active--;
+               box->events[hwc->idx] = NULL;
+               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+               hwc->state |= PERF_HES_STOPPED;
+
+               if (box->n_active == 0) {
+                       uncore_disable_box(box);
+                       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 uncore_pmu_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;
+       int assign[UNCORE_PMC_IDX_MAX];
+       int i, n, ret;
+
+       if (!box)
+               return -ENODEV;
+
+       ret = n = uncore_collect_events(box, event, false);
+       if (ret < 0)
+               return ret;
+
+       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (!(flags & PERF_EF_START))
+               hwc->state |= PERF_HES_ARCH;
+
+       ret = uncore_assign_events(box, assign, n);
+       if (ret)
+               return ret;
+
+       /* save events moving to new counters */
+       for (i = 0; i < box->n_events; i++) {
+               event = box->event_list[i];
+               hwc = &event->hw;
+
+               if (hwc->idx == assign[i] &&
+                       hwc->last_tag == box->tags[assign[i]])
+                       continue;
+               /*
+                * Ensure we don't accidentally enable a stopped
+                * counter simply because we rescheduled.
+                */
+               if (hwc->state & PERF_HES_STOPPED)
+                       hwc->state |= PERF_HES_ARCH;
+
+               uncore_pmu_event_stop(event, PERF_EF_UPDATE);
+       }
+
+       /* reprogram moved events into new counters */
+       for (i = 0; i < n; i++) {
+               event = box->event_list[i];
+               hwc = &event->hw;
+
+               if (hwc->idx != assign[i] ||
+                       hwc->last_tag != box->tags[assign[i]])
+                       uncore_assign_hw_event(box, event, assign[i]);
+               else if (i < box->n_events)
+                       continue;
+
+               if (hwc->state & PERF_HES_ARCH)
+                       continue;
+
+               uncore_pmu_event_start(event, 0);
+       }
+       box->n_events = n;
+
+       return 0;
+}
+
+static void uncore_pmu_event_del(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       int i;
+
+       uncore_pmu_event_stop(event, PERF_EF_UPDATE);
+
+       for (i = 0; i < box->n_events; i++) {
+               if (event == box->event_list[i]) {
+                       uncore_put_event_constraint(box, event);
+
+                       while (++i < box->n_events)
+                               box->event_list[i - 1] = box->event_list[i];
+
+                       --box->n_events;
+                       break;
+               }
+       }
+
+       event->hw.idx = -1;
+       event->hw.last_tag = ~0ULL;
+}
+
+static void uncore_pmu_event_read(struct perf_event *event)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       uncore_perf_event_update(box, event);
+}
+
+/*
+ * validation ensures the group can be loaded onto the
+ * PMU if it was the only group available.
+ */
+static int uncore_validate_group(struct intel_uncore_pmu *pmu,
+                               struct perf_event *event)
+{
+       struct perf_event *leader = event->group_leader;
+       struct intel_uncore_box *fake_box;
+       int ret = -EINVAL, n;
+
+       fake_box = uncore_alloc_box(pmu->type, smp_processor_id());
+       if (!fake_box)
+               return -ENOMEM;
+
+       fake_box->pmu = pmu;
+       /*
+        * the event is not yet connected with its
+        * siblings therefore we must first collect
+        * existing siblings, then add the new event
+        * before we can simulate the scheduling
+        */
+       n = uncore_collect_events(fake_box, leader, true);
+       if (n < 0)
+               goto out;
+
+       fake_box->n_events = n;
+       n = uncore_collect_events(fake_box, event, false);
+       if (n < 0)
+               goto out;
+
+       fake_box->n_events = n;
+
+       ret = uncore_assign_events(fake_box, NULL, n);
+out:
+       kfree(fake_box);
+       return ret;
+}
+
+int uncore_pmu_event_init(struct perf_event *event)
+{
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       struct hw_perf_event *hwc = &event->hw;
+       int ret;
+
+       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;
+
+       /*
+        * Uncore PMU does measure at all privilege level all the time.
+        * So it doesn't make sense to specify any exclude bits.
+        */
+       if (event->attr.exclude_user || event->attr.exclude_kernel ||
+                       event->attr.exclude_hv || event->attr.exclude_idle)
+               return -EINVAL;
+
+       /* Sampling not supported yet */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       /*
+        * Place all uncore events for a particular physical package
+        * onto a single cpu
+        */
+       if (event->cpu < 0)
+               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;
+
+       if (event->attr.config == UNCORE_FIXED_EVENT) {
+               /* no fixed counter */
+               if (!pmu->type->fixed_ctl)
+                       return -EINVAL;
+               /*
+                * if there is only one fixed counter, only the first pmu
+                * can access the fixed counter
+                */
+               if (pmu->type->single_fixed && pmu->pmu_idx > 0)
+                       return -EINVAL;
+               hwc->config = ~0ULL;
+       } else {
+               hwc->config = event->attr.config & pmu->type->event_mask;
+               if (pmu->type->ops->hw_config) {
+                       ret = pmu->type->ops->hw_config(box, event);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       if (event->group_leader != event)
+               ret = uncore_validate_group(pmu, event);
+       else
+               ret = 0;
+
+       return ret;
+}
+
+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->num_boxes == 1) {
+               if (strlen(pmu->type->name) > 0)
+                       sprintf(pmu->name, "uncore_%s", pmu->type->name);
+               else
+                       sprintf(pmu->name, "uncore");
+       } else {
+               sprintf(pmu->name, "uncore_%s_%d", pmu->type->name,
+                       pmu->pmu_idx);
+       }
+
+       ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
+       return ret;
+}
+
+static void __init uncore_type_exit(struct intel_uncore_type *type)
+{
+       int i;
+
+       for (i = 0; i < type->num_boxes; i++)
+               free_percpu(type->pmus[i].box);
+       kfree(type->pmus);
+       type->pmus = NULL;
+       kfree(type->attr_groups[1]);
+       type->attr_groups[1] = NULL;
+}
+
+static void uncore_types_exit(struct intel_uncore_type **types)
+{
+       int i;
+       for (i = 0; types[i]; i++)
+               uncore_type_exit(types[i]);
+}
+
+static int __init uncore_type_init(struct intel_uncore_type *type)
+{
+       struct intel_uncore_pmu *pmus;
+       struct attribute_group *events_group;
+       struct attribute **attrs;
+       int i, j;
+
+       pmus = kzalloc(sizeof(*pmus) * type->num_boxes, GFP_KERNEL);
+       if (!pmus)
+               return -ENOMEM;
+
+       type->unconstrainted = (struct event_constraint)
+               __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
+                               0, type->num_counters, 0);
+
+       for (i = 0; i < type->num_boxes; i++) {
+               pmus[i].func_id = -1;
+               pmus[i].pmu_idx = i;
+               pmus[i].type = type;
+               INIT_LIST_HEAD(&pmus[i].box_list);
+               pmus[i].box = alloc_percpu(struct intel_uncore_box *);
+               if (!pmus[i].box)
+                       goto fail;
+       }
+
+       if (type->event_descs) {
+               i = 0;
+               while (type->event_descs[i].attr.attr.name)
+                       i++;
+
+               events_group = kzalloc(sizeof(struct attribute *) * (i + 1) +
+                                       sizeof(*events_group), GFP_KERNEL);
+               if (!events_group)
+                       goto fail;
+
+               attrs = (struct attribute **)(events_group + 1);
+               events_group->name = "events";
+               events_group->attrs = attrs;
+
+               for (j = 0; j < i; j++)
+                       attrs[j] = &type->event_descs[j].attr.attr;
+
+               type->attr_groups[1] = events_group;
+       }
+
+       type->pmus = pmus;
+       return 0;
+fail:
+       uncore_type_exit(type);
+       return -ENOMEM;
+}
+
+static int __init uncore_types_init(struct intel_uncore_type **types)
+{
+       int i, ret;
+
+       for (i = 0; types[i]; i++) {
+               ret = uncore_type_init(types[i]);
+               if (ret)
+                       goto fail;
+       }
+       return 0;
+fail:
+       while (--i >= 0)
+               uncore_type_exit(types[i]);
+       return ret;
+}
+
+static struct pci_driver *uncore_pci_driver;
+static bool pcidrv_registered;
+
+/*
+ * add a pci uncore device
+ */
+static int __devinit uncore_pci_add(struct intel_uncore_type *type,
+                                   struct pci_dev *pdev)
+{
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       int i, phys_id;
+
+       phys_id = pcibus_to_physid[pdev->bus->number];
+       if (phys_id < 0)
+               return -ENODEV;
+
+       box = uncore_alloc_box(type, 0);
+       if (!box)
+               return -ENOMEM;
+
+       /*
+        * for performance monitoring unit with multiple boxes,
+        * each box has a different function id.
+        */
+       for (i = 0; i < type->num_boxes; i++) {
+               pmu = &type->pmus[i];
+               if (pmu->func_id == pdev->devfn)
+                       break;
+               if (pmu->func_id < 0) {
+                       pmu->func_id = pdev->devfn;
+                       break;
+               }
+               pmu = NULL;
+       }
+
+       if (!pmu) {
+               kfree(box);
+               return -EINVAL;
+       }
+
+       box->phys_id = phys_id;
+       box->pci_dev = pdev;
+       box->pmu = pmu;
+       uncore_box_init(box);
+       pci_set_drvdata(pdev, box);
+
+       raw_spin_lock(&uncore_box_lock);
+       list_add_tail(&box->list, &pmu->box_list);
+       raw_spin_unlock(&uncore_box_lock);
+
+       return 0;
+}
+
+static void uncore_pci_remove(struct pci_dev *pdev)
+{
+       struct intel_uncore_box *box = pci_get_drvdata(pdev);
+       struct intel_uncore_pmu *pmu = box->pmu;
+       int cpu, phys_id = pcibus_to_physid[pdev->bus->number];
+
+       if (WARN_ON_ONCE(phys_id != box->phys_id))
+               return;
+
+       raw_spin_lock(&uncore_box_lock);
+       list_del(&box->list);
+       raw_spin_unlock(&uncore_box_lock);
+
+       for_each_possible_cpu(cpu) {
+               if (*per_cpu_ptr(pmu->box, cpu) == box) {
+                       *per_cpu_ptr(pmu->box, cpu) = NULL;
+                       atomic_dec(&box->refcnt);
+               }
+       }
+
+       WARN_ON_ONCE(atomic_read(&box->refcnt) != 1);
+       kfree(box);
+}
+
+static int __devinit uncore_pci_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *id)
+{
+       struct intel_uncore_type *type;
+
+       type = (struct intel_uncore_type *)id->driver_data;
+       return uncore_pci_add(type, pdev);
+}
+
+static int __init uncore_pci_init(void)
+{
+       int ret;
+
+       switch (boot_cpu_data.x86_model) {
+       case 45: /* Sandy Bridge-EP */
+               pci_uncores = snbep_pci_uncores;
+               uncore_pci_driver = &snbep_uncore_pci_driver;
+               snbep_pci2phy_map_init();
+               break;
+       default:
+               return 0;
+       }
+
+       ret = uncore_types_init(pci_uncores);
+       if (ret)
+               return ret;
+
+       uncore_pci_driver->probe = uncore_pci_probe;
+       uncore_pci_driver->remove = uncore_pci_remove;
+
+       ret = pci_register_driver(uncore_pci_driver);
+       if (ret == 0)
+               pcidrv_registered = true;
+       else
+               uncore_types_exit(pci_uncores);
+
+       return ret;
+}
+
+static void __init uncore_pci_exit(void)
+{
+       if (pcidrv_registered) {
+               pcidrv_registered = false;
+               pci_unregister_driver(uncore_pci_driver);
+               uncore_types_exit(pci_uncores);
+       }
+}
+
+static void __cpuinit uncore_cpu_dying(int cpu)
+{
+       struct intel_uncore_type *type;
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       int i, j;
+
+       for (i = 0; msr_uncores[i]; i++) {
+               type = msr_uncores[i];
+               for (j = 0; j < type->num_boxes; j++) {
+                       pmu = &type->pmus[j];
+                       box = *per_cpu_ptr(pmu->box, cpu);
+                       *per_cpu_ptr(pmu->box, cpu) = NULL;
+                       if (box && atomic_dec_and_test(&box->refcnt))
+                               kfree(box);
+               }
+       }
+}
+
+static int __cpuinit uncore_cpu_starting(int cpu)
+{
+       struct intel_uncore_type *type;
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box, *exist;
+       int i, j, k, phys_id;
+
+       phys_id = topology_physical_package_id(cpu);
+
+       for (i = 0; msr_uncores[i]; i++) {
+               type = msr_uncores[i];
+               for (j = 0; j < type->num_boxes; j++) {
+                       pmu = &type->pmus[j];
+                       box = *per_cpu_ptr(pmu->box, cpu);
+                       /* called by uncore_cpu_init? */
+                       if (box && box->phys_id >= 0) {
+                               uncore_box_init(box);
+                               continue;
+                       }
+
+                       for_each_online_cpu(k) {
+                               exist = *per_cpu_ptr(pmu->box, k);
+                               if (exist && exist->phys_id == phys_id) {
+                                       atomic_inc(&exist->refcnt);
+                                       *per_cpu_ptr(pmu->box, cpu) = exist;
+                                       kfree(box);
+                                       box = NULL;
+                                       break;
+                               }
+                       }
+
+                       if (box) {
+                               box->phys_id = phys_id;
+                               uncore_box_init(box);
+                       }
+               }
+       }
+       return 0;
+}
+
+static int __cpuinit uncore_cpu_prepare(int cpu, int phys_id)
+{
+       struct intel_uncore_type *type;
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       int i, j;
+
+       for (i = 0; msr_uncores[i]; i++) {
+               type = msr_uncores[i];
+               for (j = 0; j < type->num_boxes; j++) {
+                       pmu = &type->pmus[j];
+                       if (pmu->func_id < 0)
+                               pmu->func_id = j;
+
+                       box = uncore_alloc_box(type, cpu);
+                       if (!box)
+                               return -ENOMEM;
+
+                       box->pmu = pmu;
+                       box->phys_id = phys_id;
+                       *per_cpu_ptr(pmu->box, cpu) = box;
+               }
+       }
+       return 0;
+}
+
+static void __cpuinit uncore_change_context(struct intel_uncore_type **uncores,
+                                           int old_cpu, int new_cpu)
+{
+       struct intel_uncore_type *type;
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       int i, j;
+
+       for (i = 0; uncores[i]; i++) {
+               type = uncores[i];
+               for (j = 0; j < type->num_boxes; j++) {
+                       pmu = &type->pmus[j];
+                       if (old_cpu < 0)
+                               box = uncore_pmu_to_box(pmu, new_cpu);
+                       else
+                               box = uncore_pmu_to_box(pmu, old_cpu);
+                       if (!box)
+                               continue;
+
+                       if (old_cpu < 0) {
+                               WARN_ON_ONCE(box->cpu != -1);
+                               box->cpu = new_cpu;
+                               continue;
+                       }
+
+                       WARN_ON_ONCE(box->cpu != old_cpu);
+                       if (new_cpu >= 0) {
+                               uncore_pmu_cancel_hrtimer(box);
+                               perf_pmu_migrate_context(&pmu->pmu,
+                                               old_cpu, new_cpu);
+                               box->cpu = new_cpu;
+                       } else {
+                               box->cpu = -1;
+                       }
+               }
+       }
+}
+
+static void __cpuinit uncore_event_exit_cpu(int cpu)
+{
+       int i, phys_id, target;
+
+       /* if exiting cpu is used for collecting uncore events */
+       if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
+               return;
+
+       /* find a new cpu to collect uncore events */
+       phys_id = topology_physical_package_id(cpu);
+       target = -1;
+       for_each_online_cpu(i) {
+               if (i == cpu)
+                       continue;
+               if (phys_id == topology_physical_package_id(i)) {
+                       target = i;
+                       break;
+               }
+       }
+
+       /* migrate uncore events to the new cpu */
+       if (target >= 0)
+               cpumask_set_cpu(target, &uncore_cpu_mask);
+
+       uncore_change_context(msr_uncores, cpu, target);
+       uncore_change_context(pci_uncores, cpu, target);
+}
+
+static void __cpuinit uncore_event_init_cpu(int cpu)
+{
+       int i, phys_id;
+
+       phys_id = topology_physical_package_id(cpu);
+       for_each_cpu(i, &uncore_cpu_mask) {
+               if (phys_id == topology_physical_package_id(i))
+                       return;
+       }
+
+       cpumask_set_cpu(cpu, &uncore_cpu_mask);
+
+       uncore_change_context(msr_uncores, -1, cpu);
+       uncore_change_context(pci_uncores, -1, cpu);
+}
+
+static int __cpuinit uncore_cpu_notifier(struct notifier_block *self,
+                                        unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long)hcpu;
+
+       /* allocate/free data structure for uncore box */
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+               uncore_cpu_prepare(cpu, -1);
+               break;
+       case CPU_STARTING:
+               uncore_cpu_starting(cpu);
+               break;
+       case CPU_UP_CANCELED:
+       case CPU_DYING:
+               uncore_cpu_dying(cpu);
+               break;
+       default:
+               break;
+       }
+
+       /* select the cpu that collects uncore events */
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_DOWN_FAILED:
+       case CPU_STARTING:
+               uncore_event_init_cpu(cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+               uncore_event_exit_cpu(cpu);
+               break;
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block uncore_cpu_nb __cpuinitdata = {
+       .notifier_call = uncore_cpu_notifier,
+       /*
+        * to migrate uncore events, our notifier should be executed
+        * before perf core's notifier.
+        */
+       .priority = CPU_PRI_PERF + 1,
+};
+
+static void __init uncore_cpu_setup(void *dummy)
+{
+       uncore_cpu_starting(smp_processor_id());
+}
+
+static int __init uncore_cpu_init(void)
+{
+       int ret, cpu, max_cores;
+
+       max_cores = boot_cpu_data.x86_max_cores;
+       switch (boot_cpu_data.x86_model) {
+       case 26: /* Nehalem */
+       case 30:
+       case 37: /* Westmere */
+       case 44:
+               msr_uncores = nhm_msr_uncores;
+               break;
+       case 42: /* Sandy Bridge */
+               if (snb_uncore_cbox.num_boxes > max_cores)
+                       snb_uncore_cbox.num_boxes = max_cores;
+               msr_uncores = snb_msr_uncores;
+               break;
+       case 45: /* Sandy Birdge-EP */
+               if (snbep_uncore_cbox.num_boxes > max_cores)
+                       snbep_uncore_cbox.num_boxes = max_cores;
+               msr_uncores = snbep_msr_uncores;
+               break;
+       default:
+               return 0;
+       }
+
+       ret = uncore_types_init(msr_uncores);
+       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;
+}
+
+static int __init uncore_pmus_register(void)
+{
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_type *type;
+       int i, j;
+
+       for (i = 0; msr_uncores[i]; i++) {
+               type = msr_uncores[i];
+               for (j = 0; j < type->num_boxes; j++) {
+                       pmu = &type->pmus[j];
+                       uncore_pmu_register(pmu);
+               }
+       }
+
+       for (i = 0; pci_uncores[i]; i++) {
+               type = pci_uncores[i];
+               for (j = 0; j < type->num_boxes; j++) {
+                       pmu = &type->pmus[j];
+                       uncore_pmu_register(pmu);
+               }
+       }
+
+       return 0;
+}
+
+static int __init intel_uncore_init(void)
+{
+       int ret;
+
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+               return -ENODEV;
+
+       ret = uncore_pci_init();
+       if (ret)
+               goto fail;
+       ret = uncore_cpu_init();
+       if (ret) {
+               uncore_pci_exit();
+               goto fail;
+       }
+
+       uncore_pmus_register();
+       return 0;
+fail:
+       return ret;
+}
+device_initcall(intel_uncore_init);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
new file mode 100644 (file)
index 0000000..b13e9ea
--- /dev/null
@@ -0,0 +1,424 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/perf_event.h>
+#include "perf_event.h"
+
+#define UNCORE_PMU_NAME_LEN            32
+#define UNCORE_BOX_HASH_SIZE           8
+
+#define UNCORE_PMU_HRTIMER_INTERVAL    (60 * NSEC_PER_SEC)
+
+#define UNCORE_FIXED_EVENT             0xff
+#define UNCORE_PMC_IDX_MAX_GENERIC     8
+#define UNCORE_PMC_IDX_FIXED           UNCORE_PMC_IDX_MAX_GENERIC
+#define UNCORE_PMC_IDX_MAX             (UNCORE_PMC_IDX_FIXED + 1)
+
+#define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
+
+/* SNB event control */
+#define SNB_UNC_CTL_EV_SEL_MASK                        0x000000ff
+#define SNB_UNC_CTL_UMASK_MASK                 0x0000ff00
+#define SNB_UNC_CTL_EDGE_DET                   (1 << 18)
+#define SNB_UNC_CTL_EN                         (1 << 22)
+#define SNB_UNC_CTL_INVERT                     (1 << 23)
+#define SNB_UNC_CTL_CMASK_MASK                 0x1f000000
+#define NHM_UNC_CTL_CMASK_MASK                 0xff000000
+#define NHM_UNC_FIXED_CTR_CTL_EN               (1 << 0)
+
+#define SNB_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                SNB_UNC_CTL_UMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET | \
+                                                SNB_UNC_CTL_INVERT | \
+                                                SNB_UNC_CTL_CMASK_MASK)
+
+#define NHM_UNC_RAW_EVENT_MASK                 (SNB_UNC_CTL_EV_SEL_MASK | \
+                                                SNB_UNC_CTL_UMASK_MASK | \
+                                                SNB_UNC_CTL_EDGE_DET | \
+                                                SNB_UNC_CTL_INVERT | \
+                                                NHM_UNC_CTL_CMASK_MASK)
+
+/* SNB global control register */
+#define SNB_UNC_PERF_GLOBAL_CTL                 0x391
+#define SNB_UNC_FIXED_CTR_CTRL                  0x394
+#define SNB_UNC_FIXED_CTR                       0x395
+
+/* SNB uncore global control */
+#define SNB_UNC_GLOBAL_CTL_CORE_ALL             ((1 << 4) - 1)
+#define SNB_UNC_GLOBAL_CTL_EN                   (1 << 29)
+
+/* SNB Cbo register */
+#define SNB_UNC_CBO_0_PERFEVTSEL0               0x700
+#define SNB_UNC_CBO_0_PER_CTR0                  0x706
+#define SNB_UNC_CBO_MSR_OFFSET                  0x10
+
+/* NHM global control register */
+#define NHM_UNC_PERF_GLOBAL_CTL                 0x391
+#define NHM_UNC_FIXED_CTR                       0x394
+#define NHM_UNC_FIXED_CTR_CTRL                  0x395
+
+/* NHM uncore global control */
+#define NHM_UNC_GLOBAL_CTL_EN_PC_ALL            ((1ULL << 8) - 1)
+#define NHM_UNC_GLOBAL_CTL_EN_FC                (1ULL << 32)
+
+/* NHM uncore register */
+#define NHM_UNC_PERFEVTSEL0                     0x3c0
+#define NHM_UNC_UNCORE_PMC0                     0x3b0
+
+/* SNB-EP Box level control */
+#define SNBEP_PMON_BOX_CTL_RST_CTRL    (1 << 0)
+#define SNBEP_PMON_BOX_CTL_RST_CTRS    (1 << 1)
+#define SNBEP_PMON_BOX_CTL_FRZ         (1 << 8)
+#define SNBEP_PMON_BOX_CTL_FRZ_EN      (1 << 16)
+#define SNBEP_PMON_BOX_CTL_INT         (SNBEP_PMON_BOX_CTL_RST_CTRL | \
+                                        SNBEP_PMON_BOX_CTL_RST_CTRS | \
+                                        SNBEP_PMON_BOX_CTL_FRZ_EN)
+/* SNB-EP event control */
+#define SNBEP_PMON_CTL_EV_SEL_MASK     0x000000ff
+#define SNBEP_PMON_CTL_UMASK_MASK      0x0000ff00
+#define SNBEP_PMON_CTL_RST             (1 << 17)
+#define SNBEP_PMON_CTL_EDGE_DET                (1 << 18)
+#define SNBEP_PMON_CTL_EV_SEL_EXT      (1 << 21)       /* only for QPI */
+#define SNBEP_PMON_CTL_EN              (1 << 22)
+#define SNBEP_PMON_CTL_INVERT          (1 << 23)
+#define SNBEP_PMON_CTL_TRESH_MASK      0xff000000
+#define SNBEP_PMON_RAW_EVENT_MASK      (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                        SNBEP_PMON_CTL_UMASK_MASK | \
+                                        SNBEP_PMON_CTL_EDGE_DET | \
+                                        SNBEP_PMON_CTL_INVERT | \
+                                        SNBEP_PMON_CTL_TRESH_MASK)
+
+/* SNB-EP Ubox event control */
+#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK                0x1f000000
+#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK                \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PMON_CTL_UMASK_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PMON_CTL_INVERT | \
+                                SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+
+#define SNBEP_CBO_PMON_CTL_TID_EN              (1 << 19)
+#define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK      (SNBEP_PMON_RAW_EVENT_MASK | \
+                                                SNBEP_CBO_PMON_CTL_TID_EN)
+
+/* SNB-EP PCU event control */
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK    0x0000c000
+#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK      0x1f000000
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT      (1 << 30)
+#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET    (1 << 31)
+#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK      \
+                               (SNBEP_PMON_CTL_EV_SEL_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+                                SNBEP_PMON_CTL_EDGE_DET | \
+                                SNBEP_PMON_CTL_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+                                SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+
+/* SNB-EP pci control register */
+#define SNBEP_PCI_PMON_BOX_CTL                 0xf4
+#define SNBEP_PCI_PMON_CTL0                    0xd8
+/* SNB-EP pci counter register */
+#define SNBEP_PCI_PMON_CTR0                    0xa0
+
+/* SNB-EP home agent register */
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0       0x40
+#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1       0x44
+#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH      0x48
+/* SNB-EP memory controller register */
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL                0xf0
+#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR                0xd0
+/* SNB-EP QPI register */
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0         0x228
+#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1         0x22c
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0          0x238
+#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1          0x23c
+
+/* SNB-EP Ubox register */
+#define SNBEP_U_MSR_PMON_CTR0                  0xc16
+#define SNBEP_U_MSR_PMON_CTL0                  0xc10
+
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL                0xc08
+#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR                0xc09
+
+/* SNB-EP Cbo register */
+#define SNBEP_C0_MSR_PMON_CTR0                 0xd16
+#define SNBEP_C0_MSR_PMON_CTL0                 0xd10
+#define SNBEP_C0_MSR_PMON_BOX_CTL              0xd04
+#define SNBEP_C0_MSR_PMON_BOX_FILTER           0xd14
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK     0xfffffc1f
+#define SNBEP_CBO_MSR_OFFSET                   0x20
+
+/* SNB-EP PCU register */
+#define SNBEP_PCU_MSR_PMON_CTR0                        0xc36
+#define SNBEP_PCU_MSR_PMON_CTL0                        0xc30
+#define SNBEP_PCU_MSR_PMON_BOX_CTL             0xc24
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER          0xc34
+#define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK     0xffffffff
+#define SNBEP_PCU_MSR_CORE_C3_CTR              0x3fc
+#define SNBEP_PCU_MSR_CORE_C6_CTR              0x3fd
+
+struct intel_uncore_ops;
+struct intel_uncore_pmu;
+struct intel_uncore_box;
+struct uncore_event_desc;
+
+struct intel_uncore_type {
+       const char *name;
+       int num_counters;
+       int num_boxes;
+       int perf_ctr_bits;
+       int fixed_ctr_bits;
+       unsigned perf_ctr;
+       unsigned event_ctl;
+       unsigned event_mask;
+       unsigned fixed_ctr;
+       unsigned fixed_ctl;
+       unsigned box_ctl;
+       unsigned msr_offset;
+       unsigned num_shared_regs:8;
+       unsigned single_fixed:1;
+       struct event_constraint unconstrainted;
+       struct event_constraint *constraints;
+       struct intel_uncore_pmu *pmus;
+       struct intel_uncore_ops *ops;
+       struct uncore_event_desc *event_descs;
+       const struct attribute_group *attr_groups[3];
+};
+
+#define format_group attr_groups[0]
+
+struct intel_uncore_ops {
+       void (*init_box)(struct intel_uncore_box *);
+       void (*disable_box)(struct intel_uncore_box *);
+       void (*enable_box)(struct intel_uncore_box *);
+       void (*disable_event)(struct intel_uncore_box *, struct perf_event *);
+       void (*enable_event)(struct intel_uncore_box *, struct perf_event *);
+       u64 (*read_counter)(struct intel_uncore_box *, struct perf_event *);
+       int (*hw_config)(struct intel_uncore_box *, struct perf_event *);
+       struct event_constraint *(*get_constraint)(struct intel_uncore_box *,
+                                                  struct perf_event *);
+       void (*put_constraint)(struct intel_uncore_box *, struct perf_event *);
+};
+
+struct intel_uncore_pmu {
+       struct pmu pmu;
+       char name[UNCORE_PMU_NAME_LEN];
+       int pmu_idx;
+       int func_id;
+       struct intel_uncore_type *type;
+       struct intel_uncore_box ** __percpu box;
+       struct list_head box_list;
+};
+
+struct intel_uncore_extra_reg {
+       raw_spinlock_t lock;
+       u64 config1;
+       atomic_t ref;
+};
+
+struct intel_uncore_box {
+       int phys_id;
+       int n_active;   /* number of active events */
+       int n_events;
+       int cpu;        /* cpu to collect events */
+       unsigned long flags;
+       atomic_t refcnt;
+       struct perf_event *events[UNCORE_PMC_IDX_MAX];
+       struct perf_event *event_list[UNCORE_PMC_IDX_MAX];
+       unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)];
+       u64 tags[UNCORE_PMC_IDX_MAX];
+       struct pci_dev *pci_dev;
+       struct intel_uncore_pmu *pmu;
+       struct hrtimer hrtimer;
+       struct list_head list;
+       struct intel_uncore_extra_reg shared_regs[0];
+};
+
+#define UNCORE_BOX_FLAG_INITIATED      0
+
+struct uncore_event_desc {
+       struct kobj_attribute attr;
+       const char *config;
+};
+
+#define INTEL_UNCORE_EVENT_DESC(_name, _config)                        \
+{                                                              \
+       .attr   = __ATTR(_name, 0444, uncore_event_show, NULL), \
+       .config = _config,                                      \
+}
+
+#define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format)                        \
+static ssize_t __uncore_##_var##_show(struct kobject *kobj,            \
+                               struct kobj_attribute *attr,            \
+                               char *page)                             \
+{                                                                      \
+       BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);                     \
+       return sprintf(page, _format "\n");                             \
+}                                                                      \
+static struct kobj_attribute format_attr_##_var =                      \
+       __ATTR(_name, 0444, __uncore_##_var##_show, NULL)
+
+
+static ssize_t uncore_event_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
+{
+       struct uncore_event_desc *event =
+               container_of(attr, struct uncore_event_desc, attr);
+       return sprintf(buf, "%s", event->config);
+}
+
+static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box)
+{
+       return box->pmu->type->box_ctl;
+}
+
+static inline unsigned uncore_pci_fixed_ctl(struct intel_uncore_box *box)
+{
+       return box->pmu->type->fixed_ctl;
+}
+
+static inline unsigned uncore_pci_fixed_ctr(struct intel_uncore_box *box)
+{
+       return box->pmu->type->fixed_ctr;
+}
+
+static inline
+unsigned uncore_pci_event_ctl(struct intel_uncore_box *box, int idx)
+{
+       return idx * 4 + box->pmu->type->event_ctl;
+}
+
+static inline
+unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx)
+{
+       return idx * 8 + box->pmu->type->perf_ctr;
+}
+
+static inline
+unsigned uncore_msr_box_ctl(struct intel_uncore_box *box)
+{
+       if (!box->pmu->type->box_ctl)
+               return 0;
+       return box->pmu->type->box_ctl +
+               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box)
+{
+       if (!box->pmu->type->fixed_ctl)
+               return 0;
+       return box->pmu->type->fixed_ctl +
+               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
+{
+       return box->pmu->type->fixed_ctr +
+               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx)
+{
+       return idx + box->pmu->type->event_ctl +
+               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
+{
+       return idx + box->pmu->type->perf_ctr +
+               box->pmu->type->msr_offset * box->pmu->pmu_idx;
+}
+
+static inline
+unsigned uncore_fixed_ctl(struct intel_uncore_box *box)
+{
+       if (box->pci_dev)
+               return uncore_pci_fixed_ctl(box);
+       else
+               return uncore_msr_fixed_ctl(box);
+}
+
+static inline
+unsigned uncore_fixed_ctr(struct intel_uncore_box *box)
+{
+       if (box->pci_dev)
+               return uncore_pci_fixed_ctr(box);
+       else
+               return uncore_msr_fixed_ctr(box);
+}
+
+static inline
+unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx)
+{
+       if (box->pci_dev)
+               return uncore_pci_event_ctl(box, idx);
+       else
+               return uncore_msr_event_ctl(box, idx);
+}
+
+static inline
+unsigned uncore_perf_ctr(struct intel_uncore_box *box, int idx)
+{
+       if (box->pci_dev)
+               return uncore_pci_perf_ctr(box, idx);
+       else
+               return uncore_msr_perf_ctr(box, idx);
+}
+
+static inline int uncore_perf_ctr_bits(struct intel_uncore_box *box)
+{
+       return box->pmu->type->perf_ctr_bits;
+}
+
+static inline int uncore_fixed_ctr_bits(struct intel_uncore_box *box)
+{
+       return box->pmu->type->fixed_ctr_bits;
+}
+
+static inline int uncore_num_counters(struct intel_uncore_box *box)
+{
+       return box->pmu->type->num_counters;
+}
+
+static inline void uncore_disable_box(struct intel_uncore_box *box)
+{
+       if (box->pmu->type->ops->disable_box)
+               box->pmu->type->ops->disable_box(box);
+}
+
+static inline void uncore_enable_box(struct intel_uncore_box *box)
+{
+       if (box->pmu->type->ops->enable_box)
+               box->pmu->type->ops->enable_box(box);
+}
+
+static inline void uncore_disable_event(struct intel_uncore_box *box,
+                               struct perf_event *event)
+{
+       box->pmu->type->ops->disable_event(box, event);
+}
+
+static inline void uncore_enable_event(struct intel_uncore_box *box,
+                               struct perf_event *event)
+{
+       box->pmu->type->ops->enable_event(box, event);
+}
+
+static inline u64 uncore_read_counter(struct intel_uncore_box *box,
+                               struct perf_event *event)
+{
+       return box->pmu->type->ops->read_counter(box, event);
+}
+
+static inline void uncore_box_init(struct intel_uncore_box *box)
+{
+       if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) {
+               if (box->pmu->type->ops->init_box)
+                       box->pmu->type->ops->init_box(box);
+       }
+}
index 47124a73dd73098e1179f174a0a6cb56ea07f227..92c7e39a079ffd738ae33fc9a721631111bb5596 100644 (file)
@@ -895,8 +895,8 @@ static void p4_pmu_disable_pebs(void)
         * So at moment let leave metrics turned on forever -- it's
         * ok for now but need to be revisited!
         *
-        * (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE, (u64)0);
-        * (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT, (u64)0);
+        * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, (u64)0);
+        * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, (u64)0);
         */
 }
 
@@ -909,7 +909,7 @@ static inline void p4_pmu_disable_event(struct perf_event *event)
         * state we need to clear P4_CCCR_OVF, otherwise interrupt get
         * asserted again and again
         */
-       (void)checking_wrmsrl(hwc->config_base,
+       (void)wrmsrl_safe(hwc->config_base,
                (u64)(p4_config_unpack_cccr(hwc->config)) &
                        ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED);
 }
@@ -943,8 +943,8 @@ static void p4_pmu_enable_pebs(u64 config)
 
        bind = &p4_pebs_bind_map[idx];
 
-       (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE,     (u64)bind->metric_pebs);
-       (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT,  (u64)bind->metric_vert);
+       (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, (u64)bind->metric_pebs);
+       (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT,      (u64)bind->metric_vert);
 }
 
 static void p4_pmu_enable_event(struct perf_event *event)
@@ -978,8 +978,8 @@ static void p4_pmu_enable_event(struct perf_event *event)
         */
        p4_pmu_enable_pebs(hwc->config);
 
-       (void)checking_wrmsrl(escr_addr, escr_conf);
-       (void)checking_wrmsrl(hwc->config_base,
+       (void)wrmsrl_safe(escr_addr, escr_conf);
+       (void)wrmsrl_safe(hwc->config_base,
                                (cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE);
 }
 
@@ -1325,7 +1325,7 @@ __init int p4_pmu_init(void)
        unsigned int low, high;
 
        /* If we get stripped -- indexing fails */
-       BUILD_BUG_ON(ARCH_P4_MAX_CCCR > X86_PMC_MAX_GENERIC);
+       BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC);
 
        rdmsr(MSR_IA32_MISC_ENABLE, low, high);
        if (!(low & (1 << 7))) {
index 32bcfc7dd2300d2043245e22a2351dfa65615484..e4dd0f7a04535f09b83d47d95868bcc1c152dff3 100644 (file)
@@ -71,7 +71,7 @@ p6_pmu_disable_event(struct perf_event *event)
        if (cpuc->enabled)
                val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-       (void)checking_wrmsrl(hwc->config_base, val);
+       (void)wrmsrl_safe(hwc->config_base, val);
 }
 
 static void p6_pmu_enable_event(struct perf_event *event)
@@ -84,7 +84,7 @@ static void p6_pmu_enable_event(struct perf_event *event)
        if (cpuc->enabled)
                val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 
-       (void)checking_wrmsrl(hwc->config_base, val);
+       (void)wrmsrl_safe(hwc->config_base, val);
 }
 
 PMU_FORMAT_ATTR(event, "config:0-7"    );
index 571246d81edf38da34a533391ec3841c54b45d8b..ae42418bc50f23f83d92f68e4e771daf36652978 100644 (file)
@@ -27,8 +27,8 @@ static int die_counter;
 
 void printk_address(unsigned long address, int reliable)
 {
-       printk(" [<%p>] %s%pB\n", (void *) address,
-                       reliable ? "" : "? ", (void *) address);
+       pr_cont(" [<%p>] %s%pB\n",
+               (void *)address, reliable ? "" : "? ", (void *)address);
 }
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -271,6 +271,7 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
                        current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
                return 1;
 
+       print_modules();
        show_regs(regs);
 #ifdef CONFIG_X86_32
        if (user_mode_vm(regs)) {
index e0b1d783daabfb94fcd2b85ff54ffcc7709a2a16..1038a417ea531f18fcfeacddd589440989a2a1d0 100644 (file)
@@ -73,11 +73,11 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
                if (kstack_end(stack))
                        break;
                if (i && ((i % STACKSLOTS_PER_LINE) == 0))
-                       printk(KERN_CONT "\n");
-               printk(KERN_CONT " %08lx", *stack++);
+                       pr_cont("\n");
+               pr_cont(" %08lx", *stack++);
                touch_nmi_watchdog();
        }
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
        show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
@@ -86,12 +86,11 @@ void show_regs(struct pt_regs *regs)
 {
        int i;
 
-       print_modules();
        __show_regs(regs, !user_mode_vm(regs));
 
-       printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
-               TASK_COMM_LEN, current->comm, task_pid_nr(current),
-               current_thread_info(), current, task_thread_info(current));
+       pr_emerg("Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
+                TASK_COMM_LEN, current->comm, task_pid_nr(current),
+                current_thread_info(), current, task_thread_info(current));
        /*
         * When in-kernel, we also print out the stack and code at the
         * time of the fault..
@@ -102,10 +101,10 @@ void show_regs(struct pt_regs *regs)
                unsigned char c;
                u8 *ip;
 
-               printk(KERN_EMERG "Stack:\n");
+               pr_emerg("Stack:\n");
                show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
 
-               printk(KERN_EMERG "Code: ");
+               pr_emerg("Code:");
 
                ip = (u8 *)regs->ip - code_prologue;
                if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
@@ -116,16 +115,16 @@ void show_regs(struct pt_regs *regs)
                for (i = 0; i < code_len; i++, ip++) {
                        if (ip < (u8 *)PAGE_OFFSET ||
                                        probe_kernel_address(ip, c)) {
-                               printk(KERN_CONT " Bad EIP value.");
+                               pr_cont("  Bad EIP value.");
                                break;
                        }
                        if (ip == (u8 *)regs->ip)
-                               printk(KERN_CONT "<%02x> ", c);
+                               pr_cont(" <%02x>", c);
                        else
-                               printk(KERN_CONT "%02x ", c);
+                               pr_cont(" %02x", c);
                }
        }
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 }
 
 int is_valid_bugaddr(unsigned long ip)
index 791b76122aa8b0b627eb39e3ac6028701a9a868c..b653675d5288476c2f864772fa63e4739f9de06f 100644 (file)
@@ -228,20 +228,20 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
                if (stack >= irq_stack && stack <= irq_stack_end) {
                        if (stack == irq_stack_end) {
                                stack = (unsigned long *) (irq_stack_end[-1]);
-                               printk(KERN_CONT " <EOI> ");
+                               pr_cont(" <EOI> ");
                        }
                } else {
                if (((long) stack & (THREAD_SIZE-1)) == 0)
                        break;
                }
                if (i && ((i % STACKSLOTS_PER_LINE) == 0))
-                       printk(KERN_CONT "\n");
-               printk(KERN_CONT " %016lx", *stack++);
+                       pr_cont("\n");
+               pr_cont(" %016lx", *stack++);
                touch_nmi_watchdog();
        }
        preempt_enable();
 
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
        show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
@@ -254,10 +254,9 @@ void show_regs(struct pt_regs *regs)
 
        sp = regs->sp;
        printk("CPU %d ", cpu);
-       print_modules();
        __show_regs(regs, 1);
-       printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
-               cur->comm, cur->pid, task_thread_info(cur), cur);
+       printk(KERN_DEFAULT "Process %s (pid: %d, threadinfo %p, task %p)\n",
+              cur->comm, cur->pid, task_thread_info(cur), cur);
 
        /*
         * When in-kernel, we also print out the stack and code at the
@@ -284,16 +283,16 @@ void show_regs(struct pt_regs *regs)
                for (i = 0; i < code_len; i++, ip++) {
                        if (ip < (u8 *)PAGE_OFFSET ||
                                        probe_kernel_address(ip, c)) {
-                               printk(KERN_CONT " Bad RIP value.");
+                               pr_cont(" Bad RIP value.");
                                break;
                        }
                        if (ip == (u8 *)regs->ip)
-                               printk(KERN_CONT "<%02x> ", c);
+                               pr_cont("<%02x> ", c);
                        else
-                               printk(KERN_CONT "%02x ", c);
+                               pr_cont("%02x ", c);
                }
        }
-       printk(KERN_CONT "\n");
+       pr_cont("\n");
 }
 
 int is_valid_bugaddr(unsigned long ip)
index 7d65133b51bede19fc529fd82691de2c01926f60..111f6bbd8b38afb1a175d65dbbde7a981a0de6f7 100644 (file)
@@ -1758,10 +1758,30 @@ end_repeat_nmi:
         */
        call save_paranoid
        DEFAULT_FRAME 0
+
+       /*
+        * Save off the CR2 register. If we take a page fault in the NMI then
+        * it could corrupt the CR2 value. If the NMI preempts a page fault
+        * handler before it was able to read the CR2 register, and then the
+        * NMI itself takes a page fault, the page fault that was preempted
+        * will read the information from the NMI page fault and not the
+        * origin fault. Save it off and restore it if it changes.
+        * Use the r12 callee-saved register.
+        */
+       movq %cr2, %r12
+
        /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
        movq %rsp,%rdi
        movq $-1,%rsi
        call do_nmi
+
+       /* Did the NMI take a page fault? Restore cr2 if it did */
+       movq %cr2, %rcx
+       cmpq %rcx, %r12
+       je 1f
+       movq %r12, %cr2
+1:
+       
        testl %ebx,%ebx                         /* swapgs needed? */
        jnz nmi_restore
 nmi_swapgs:
index 3dafc6003b7c4a5c177238f3f21d652cdb20ca30..1f5f1d5d2a022b21a6871c083af70f09b9def90f 100644 (file)
@@ -294,9 +294,9 @@ void fixup_irqs(void)
                raw_spin_unlock(&desc->lock);
 
                if (break_affinity && set_affinity)
-                       printk("Broke affinity for irq %i\n", irq);
+                       pr_notice("Broke affinity for irq %i\n", irq);
                else if (!set_affinity)
-                       printk("Cannot set affinity for irq %i\n", irq);
+                       pr_notice("Cannot set affinity for irq %i\n", irq);
        }
 
        /*
index fbdfc6917180f8f5379033cc408d164573d027e5..4873e62db6a18468b23736c5f4adfd2de8b3b85b 100644 (file)
@@ -87,6 +87,7 @@
 #include <asm/microcode.h>
 #include <asm/processor.h>
 #include <asm/cpu_device_id.h>
+#include <asm/perf_event.h>
 
 MODULE_DESCRIPTION("Microcode Update Driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
@@ -277,7 +278,6 @@ static int reload_for_cpu(int cpu)
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
        int err = 0;
 
-       mutex_lock(&microcode_mutex);
        if (uci->valid) {
                enum ucode_state ustate;
 
@@ -288,7 +288,6 @@ static int reload_for_cpu(int cpu)
                        if (ustate == UCODE_ERROR)
                                err = -EINVAL;
        }
-       mutex_unlock(&microcode_mutex);
 
        return err;
 }
@@ -298,19 +297,31 @@ static ssize_t reload_store(struct device *dev,
                            const char *buf, size_t size)
 {
        unsigned long val;
-       int cpu = dev->id;
-       ssize_t ret = 0;
+       int cpu;
+       ssize_t ret = 0, tmp_ret;
 
        ret = kstrtoul(buf, 0, &val);
        if (ret)
                return ret;
 
-       if (val == 1) {
-               get_online_cpus();
-               if (cpu_online(cpu))
-                       ret = reload_for_cpu(cpu);
-               put_online_cpus();
+       if (val != 1)
+               return size;
+
+       get_online_cpus();
+       mutex_lock(&microcode_mutex);
+       for_each_online_cpu(cpu) {
+               tmp_ret = reload_for_cpu(cpu);
+               if (tmp_ret != 0)
+                       pr_warn("Error reloading microcode on CPU %d\n", cpu);
+
+               /* save retval of the first encountered reload error */
+               if (!ret)
+                       ret = tmp_ret;
        }
+       if (!ret)
+               perf_check_microcode();
+       mutex_unlock(&microcode_mutex);
+       put_online_cpus();
 
        if (!ret)
                ret = size;
@@ -339,7 +350,6 @@ static DEVICE_ATTR(version, 0400, version_show, NULL);
 static DEVICE_ATTR(processor_flags, 0400, pf_show, NULL);
 
 static struct attribute *mc_default_attrs[] = {
-       &dev_attr_reload.attr,
        &dev_attr_version.attr,
        &dev_attr_processor_flags.attr,
        NULL
@@ -504,7 +514,7 @@ static struct notifier_block __refdata mc_cpu_notifier = {
 
 #ifdef MODULE
 /* Autoload on Intel and AMD systems */
-static const struct x86_cpu_id microcode_id[] = {
+static const struct x86_cpu_id __initconst microcode_id[] = {
 #ifdef CONFIG_MICROCODE_INTEL
        { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, },
 #endif
@@ -516,6 +526,16 @@ static const struct x86_cpu_id microcode_id[] = {
 MODULE_DEVICE_TABLE(x86cpu, microcode_id);
 #endif
 
+static struct attribute *cpu_root_microcode_attrs[] = {
+       &dev_attr_reload.attr,
+       NULL
+};
+
+static struct attribute_group cpu_root_microcode_group = {
+       .name  = "microcode",
+       .attrs = cpu_root_microcode_attrs,
+};
+
 static int __init microcode_init(void)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
@@ -540,16 +560,25 @@ static int __init microcode_init(void)
        mutex_lock(&microcode_mutex);
 
        error = subsys_interface_register(&mc_cpu_interface);
-
+       if (!error)
+               perf_check_microcode();
        mutex_unlock(&microcode_mutex);
        put_online_cpus();
 
        if (error)
                goto out_pdev;
 
+       error = sysfs_create_group(&cpu_subsys.dev_root->kobj,
+                                  &cpu_root_microcode_group);
+
+       if (error) {
+               pr_err("Error creating microcode group!\n");
+               goto out_driver;
+       }
+
        error = microcode_dev_init();
        if (error)
-               goto out_driver;
+               goto out_ucode_group;
 
        register_syscore_ops(&mc_syscore_ops);
        register_hotcpu_notifier(&mc_cpu_notifier);
@@ -559,7 +588,11 @@ static int __init microcode_init(void)
 
        return 0;
 
-out_driver:
+ out_ucode_group:
+       sysfs_remove_group(&cpu_subsys.dev_root->kobj,
+                          &cpu_root_microcode_group);
+
+ out_driver:
        get_online_cpus();
        mutex_lock(&microcode_mutex);
 
@@ -568,7 +601,7 @@ out_driver:
        mutex_unlock(&microcode_mutex);
        put_online_cpus();
 
-out_pdev:
+ out_pdev:
        platform_device_unregister(microcode_pdev);
        return error;
 
@@ -584,6 +617,9 @@ static void __exit microcode_exit(void)
        unregister_hotcpu_notifier(&mc_cpu_notifier);
        unregister_syscore_ops(&mc_syscore_ops);
 
+       sysfs_remove_group(&cpu_subsys.dev_root->kobj,
+                          &cpu_root_microcode_group);
+
        get_online_cpus();
        mutex_lock(&microcode_mutex);
 
index f21fd94ac89700b912ce5392c1bc7381ced99601..202494d2ec6e26ab5216ac469eaeebf29594cb7e 100644 (file)
@@ -15,6 +15,9 @@
     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/moduleloader.h>
 #include <linux/elf.h>
 #include <linux/vmalloc.h>
 #include <asm/pgtable.h>
 
 #if 0
-#define DEBUGP printk
+#define DEBUGP(fmt, ...)                               \
+       printk(KERN_DEBUG fmt, ##__VA_ARGS__)
 #else
-#define DEBUGP(fmt...)
+#define DEBUGP(fmt, ...)                               \
+do {                                                   \
+       if (0)                                          \
+               printk(KERN_DEBUG fmt, ##__VA_ARGS__);  \
+} while (0)
 #endif
 
 void *module_alloc(unsigned long size)
@@ -56,8 +64,8 @@ int apply_relocate(Elf32_Shdr *sechdrs,
        Elf32_Sym *sym;
        uint32_t *location;
 
-       DEBUGP("Applying relocate section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
+       DEBUGP("Applying relocate section %u to %u\n",
+              relsec, sechdrs[relsec].sh_info);
        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
                /* This is where to make the change */
                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -77,7 +85,7 @@ int apply_relocate(Elf32_Shdr *sechdrs,
                        *location += sym->st_value - (uint32_t)location;
                        break;
                default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                       pr_err("%s: Unknown relocation: %u\n",
                               me->name, ELF32_R_TYPE(rel[i].r_info));
                        return -ENOEXEC;
                }
@@ -97,8 +105,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
        void *loc;
        u64 val;
 
-       DEBUGP("Applying relocate section %u to %u\n", relsec,
-              sechdrs[relsec].sh_info);
+       DEBUGP("Applying relocate section %u to %u\n",
+              relsec, sechdrs[relsec].sh_info);
        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
                /* This is where to make the change */
                loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -110,8 +118,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        + ELF64_R_SYM(rel[i].r_info);
 
                DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
-                       (int)ELF64_R_TYPE(rel[i].r_info),
-                       sym->st_value, rel[i].r_addend, (u64)loc);
+                      (int)ELF64_R_TYPE(rel[i].r_info),
+                      sym->st_value, rel[i].r_addend, (u64)loc);
 
                val = sym->st_value + rel[i].r_addend;
 
@@ -140,7 +148,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
 #endif
                        break;
                default:
-                       printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n",
+                       pr_err("%s: Unknown rela relocation: %llu\n",
                               me->name, ELF64_R_TYPE(rel[i].r_info));
                        return -ENOEXEC;
                }
@@ -148,9 +156,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
        return 0;
 
 overflow:
-       printk(KERN_ERR "overflow in relocation type %d val %Lx\n",
+       pr_err("overflow in relocation type %d val %Lx\n",
               (int)ELF64_R_TYPE(rel[i].r_info), val);
-       printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n",
+       pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
               me->name);
        return -ENOEXEC;
 }
index a0b2f84457bebfb88de00f547c9b8db930abca5a..f84f5c57de35b0bb5693067c3799de8093ad237e 100644 (file)
@@ -365,8 +365,9 @@ static __kprobes void default_do_nmi(struct pt_regs *regs)
 #ifdef CONFIG_X86_32
 /*
  * For i386, NMIs use the same stack as the kernel, and we can
- * add a workaround to the iret problem in C. Simply have 3 states
- * the NMI can be in.
+ * add a workaround to the iret problem in C (preventing nested
+ * NMIs if an NMI takes a trap). Simply have 3 states the NMI
+ * can be in:
  *
  *  1) not running
  *  2) executing
@@ -383,32 +384,50 @@ static __kprobes void default_do_nmi(struct pt_regs *regs)
  * If an NMI hits a breakpoint that executes an iret, another
  * NMI can preempt it. We do not want to allow this new NMI
  * to run, but we want to execute it when the first one finishes.
- * We set the state to "latched", and the first NMI will perform
- * an cmpxchg on the state, and if it doesn't successfully
- * reset the state to "not running" it will restart the next
- * NMI.
+ * We set the state to "latched", and the exit of the first NMI will
+ * perform a dec_return, if the result is zero (NOT_RUNNING), then
+ * it will simply exit the NMI handler. If not, the dec_return
+ * would have set the state to NMI_EXECUTING (what we want it to
+ * be when we are running). In this case, we simply jump back
+ * to rerun the NMI handler again, and restart the 'latched' NMI.
+ *
+ * No trap (breakpoint or page fault) should be hit before nmi_restart,
+ * thus there is no race between the first check of state for NOT_RUNNING
+ * and setting it to NMI_EXECUTING. The HW will prevent nested NMIs
+ * at this point.
+ *
+ * In case the NMI takes a page fault, we need to save off the CR2
+ * because the NMI could have preempted another page fault and corrupt
+ * the CR2 that is about to be read. As nested NMIs must be restarted
+ * and they can not take breakpoints or page faults, the update of the
+ * CR2 must be done before converting the nmi state back to NOT_RUNNING.
+ * Otherwise, there would be a race of another nested NMI coming in
+ * after setting state to NOT_RUNNING but before updating the nmi_cr2.
  */
 enum nmi_states {
-       NMI_NOT_RUNNING,
+       NMI_NOT_RUNNING = 0,
        NMI_EXECUTING,
        NMI_LATCHED,
 };
 static DEFINE_PER_CPU(enum nmi_states, nmi_state);
+static DEFINE_PER_CPU(unsigned long, nmi_cr2);
 
 #define nmi_nesting_preprocess(regs)                                   \
        do {                                                            \
-               if (__get_cpu_var(nmi_state) != NMI_NOT_RUNNING) {      \
-                       __get_cpu_var(nmi_state) = NMI_LATCHED;         \
+               if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {      \
+                       this_cpu_write(nmi_state, NMI_LATCHED);         \
                        return;                                         \
                }                                                       \
-       nmi_restart:                                                    \
-               __get_cpu_var(nmi_state) = NMI_EXECUTING;               \
-       } while (0)
+               this_cpu_write(nmi_state, NMI_EXECUTING);               \
+               this_cpu_write(nmi_cr2, read_cr2());                    \
+       } while (0);                                                    \
+       nmi_restart:
 
 #define nmi_nesting_postprocess()                                      \
        do {                                                            \
-               if (cmpxchg(&__get_cpu_var(nmi_state),                  \
-                   NMI_EXECUTING, NMI_NOT_RUNNING) != NMI_EXECUTING)   \
+               if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))     \
+                       write_cr2(this_cpu_read(nmi_cr2));              \
+               if (this_cpu_dec_return(nmi_state))                     \
                        goto nmi_restart;                               \
        } while (0)
 #else /* x86_64 */
index 149b8d9c6ad45a199cfa1f55b17df3562afe4127..6d9582ec0324936646da2b537602ae267b6a4a64 100644 (file)
@@ -42,7 +42,8 @@ static int __init nmi_unk_cb(unsigned int val, struct pt_regs *regs)
 static void __init init_nmi_testsuite(void)
 {
        /* trap all the unknown NMIs we may generate */
-       register_nmi_handler_initonly(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk");
+       register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk",
+                       __initdata);
 }
 
 static void __init cleanup_nmi_testsuite(void)
@@ -64,8 +65,8 @@ static void __init test_nmi_ipi(struct cpumask *mask)
 {
        unsigned long timeout;
 
-       if (register_nmi_handler_initonly(NMI_LOCAL, test_nmi_ipi_callback,
-                                NMI_FLAG_FIRST, "nmi_selftest")) {
+       if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback,
+                                NMI_FLAG_FIRST, "nmi_selftest", __initdata)) {
                nmi_fail = FAILURE;
                return;
        }
index 9ce885996fd718bc80b5f0bf52efec81e27b3b2d..17fff18a103104431c0e10e1543af6f027f64f72 100644 (file)
@@ -352,9 +352,7 @@ struct pv_cpu_ops pv_cpu_ops = {
 #endif
        .wbinvd = native_wbinvd,
        .read_msr = native_read_msr_safe,
-       .rdmsr_regs = native_rdmsr_safe_regs,
        .write_msr = native_write_msr_safe,
-       .wrmsr_regs = native_wrmsr_safe_regs,
        .read_tsc = native_read_tsc,
        .read_pmc = native_read_pmc,
        .read_tscp = native_read_tscp,
index b72838bae64ab296bfd0bdd9e63297132d6c56e5..299d49302e7d2a46cedcd00230f8a4ed8b027c5b 100644 (file)
@@ -22,6 +22,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#define pr_fmt(fmt) "Calgary: " fmt
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -245,7 +247,7 @@ static unsigned long iommu_range_alloc(struct device *dev,
                offset = iommu_area_alloc(tbl->it_map, tbl->it_size, 0,
                                          npages, 0, boundary_size, 0);
                if (offset == ~0UL) {
-                       printk(KERN_WARNING "Calgary: IOMMU full.\n");
+                       pr_warn("IOMMU full\n");
                        spin_unlock_irqrestore(&tbl->it_lock, flags);
                        if (panic_on_overflow)
                                panic("Calgary: fix the allocator.\n");
@@ -271,8 +273,8 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
        entry = iommu_range_alloc(dev, tbl, npages);
 
        if (unlikely(entry == DMA_ERROR_CODE)) {
-               printk(KERN_WARNING "Calgary: failed to allocate %u pages in "
-                      "iommu %p\n", npages, tbl);
+               pr_warn("failed to allocate %u pages in iommu %p\n",
+                       npages, tbl);
                return DMA_ERROR_CODE;
        }
 
@@ -561,8 +563,7 @@ static void calgary_tce_cache_blast(struct iommu_table *tbl)
                i++;
        } while ((val & 0xff) != 0xff && i < 100);
        if (i == 100)
-               printk(KERN_WARNING "Calgary: PCI bus not quiesced, "
-                      "continuing anyway\n");
+               pr_warn("PCI bus not quiesced, continuing anyway\n");
 
        /* invalidate TCE cache */
        target = calgary_reg(bbar, tar_offset(tbl->it_busno));
@@ -604,8 +605,7 @@ begin:
                i++;
        } while ((val64 & 0xff) != 0xff && i < 100);
        if (i == 100)
-               printk(KERN_WARNING "CalIOC2: PCI bus not quiesced, "
-                      "continuing anyway\n");
+               pr_warn("CalIOC2: PCI bus not quiesced, continuing anyway\n");
 
        /* 3. poll Page Migration DEBUG for SoftStopFault */
        target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
@@ -617,8 +617,7 @@ begin:
                if (++count < 100)
                        goto begin;
                else {
-                       printk(KERN_WARNING "CalIOC2: too many SoftStopFaults, "
-                              "aborting TCE cache flush sequence!\n");
+                       pr_warn("CalIOC2: too many SoftStopFaults, aborting TCE cache flush sequence!\n");
                        return; /* pray for the best */
                }
        }
@@ -840,8 +839,8 @@ static void calgary_dump_error_regs(struct iommu_table *tbl)
        plssr = be32_to_cpu(readl(target));
 
        /* If no error, the agent ID in the CSR is not valid */
-       printk(KERN_EMERG "Calgary: DMA error on Calgary PHB 0x%x, "
-              "0x%08x@CSR 0x%08x@PLSSR\n", tbl->it_busno, csr, plssr);
+       pr_emerg("DMA error on Calgary PHB 0x%x, 0x%08x@CSR 0x%08x@PLSSR\n",
+                tbl->it_busno, csr, plssr);
 }
 
 static void calioc2_dump_error_regs(struct iommu_table *tbl)
@@ -867,22 +866,21 @@ static void calioc2_dump_error_regs(struct iommu_table *tbl)
        target = calgary_reg(bbar, phboff | 0x800);
        mck = be32_to_cpu(readl(target));
 
-       printk(KERN_EMERG "Calgary: DMA error on CalIOC2 PHB 0x%x\n",
-              tbl->it_busno);
+       pr_emerg("DMA error on CalIOC2 PHB 0x%x\n", tbl->it_busno);
 
-       printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
-              csr, plssr, csmr, mck);
+       pr_emerg("0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
+                csr, plssr, csmr, mck);
 
        /* dump rest of error regs */
-       printk(KERN_EMERG "Calgary: ");
+       pr_emerg("");
        for (i = 0; i < ARRAY_SIZE(errregs); i++) {
                /* err regs are at 0x810 - 0x870 */
                erroff = (0x810 + (i * 0x10));
                target = calgary_reg(bbar, phboff | erroff);
                errregs[i] = be32_to_cpu(readl(target));
-               printk("0x%08x@0x%lx ", errregs[i], erroff);
+               pr_cont("0x%08x@0x%lx ", errregs[i], erroff);
        }
-       printk("\n");
+       pr_cont("\n");
 
        /* root complex status */
        target = calgary_reg(bbar, phboff | PHB_ROOT_COMPLEX_STATUS);
index 735279e54e59a56d3f3ce97288f2d81fc98491d6..ef6a8456f719b320e36707becfa08697803f4547 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -145,16 +147,14 @@ void show_regs_common(void)
        /* Board Name is optional */
        board = dmi_get_system_info(DMI_BOARD_NAME);
 
-       printk(KERN_CONT "\n");
-       printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s",
-               current->pid, current->comm, print_tainted(),
-               init_utsname()->release,
-               (int)strcspn(init_utsname()->version, " "),
-               init_utsname()->version);
-       printk(KERN_CONT " %s %s", vendor, product);
-       if (board)
-               printk(KERN_CONT "/%s", board);
-       printk(KERN_CONT "\n");
+       printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s %s %s%s%s\n",
+              current->pid, current->comm, print_tainted(),
+              init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version,
+              vendor, product,
+              board ? "/" : "",
+              board ? board : "");
 }
 
 void flush_thread(void)
@@ -645,7 +645,7 @@ static void amd_e400_idle(void)
                        amd_e400_c1e_detected = true;
                        if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
                                mark_tsc_unstable("TSC halt in AMD C1E");
-                       printk(KERN_INFO "System has AMD C1E enabled\n");
+                       pr_info("System has AMD C1E enabled\n");
                }
        }
 
@@ -659,8 +659,7 @@ static void amd_e400_idle(void)
                         */
                        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
                                           &cpu);
-                       printk(KERN_INFO "Switch to broadcast mode on CPU%d\n",
-                              cpu);
+                       pr_info("Switch to broadcast mode on CPU%d\n", cpu);
                }
                clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
 
@@ -681,8 +680,7 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
        if (pm_idle == poll_idle && smp_num_siblings > 1) {
-               printk_once(KERN_WARNING "WARNING: polling idle and HT enabled,"
-                       " performance may degrade.\n");
+               pr_warn_once("WARNING: polling idle and HT enabled, performance may degrade\n");
        }
 #endif
        if (pm_idle)
@@ -692,11 +690,11 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
                /*
                 * One CPU supports mwait => All CPUs supports mwait
                 */
-               printk(KERN_INFO "using mwait in idle threads.\n");
+               pr_info("using mwait in idle threads\n");
                pm_idle = mwait_idle;
        } else if (cpu_has_amd_erratum(amd_erratum_400)) {
                /* E400: APIC timer interrupt does not wake up CPU from C1e */
-               printk(KERN_INFO "using AMD E400 aware idle routine\n");
+               pr_info("using AMD E400 aware idle routine\n");
                pm_idle = amd_e400_idle;
        } else
                pm_idle = default_idle;
@@ -715,7 +713,7 @@ static int __init idle_setup(char *str)
                return -EINVAL;
 
        if (!strcmp(str, "poll")) {
-               printk("using polling idle threads.\n");
+               pr_info("using polling idle threads\n");
                pm_idle = poll_idle;
                boot_option_idle_override = IDLE_POLL;
        } else if (!strcmp(str, "mwait")) {
index 61cdf7fdf09961757d7a6f8ba595df63a5a123b3..0a980c9d7cb885abb3a46d9b9572ce1ed8acca20 100644 (file)
@@ -117,10 +117,10 @@ void release_thread(struct task_struct *dead_task)
 {
        if (dead_task->mm) {
                if (dead_task->mm->context.size) {
-                       printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
-                                       dead_task->comm,
-                                       dead_task->mm->context.ldt,
-                                       dead_task->mm->context.size);
+                       pr_warn("WARNING: dead process %8s still has LDT? <%p/%d>\n",
+                               dead_task->comm,
+                               dead_task->mm->context.ldt,
+                               dead_task->mm->context.size);
                        BUG();
                }
        }
@@ -466,7 +466,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
                        task->thread.gs = addr;
                        if (doit) {
                                load_gs_index(0);
-                               ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
+                               ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, addr);
                        }
                }
                put_cpu();
@@ -494,7 +494,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
                                /* set the selector to 0 to not confuse
                                   __switch_to */
                                loadsegment(fs, 0);
-                               ret = checking_wrmsrl(MSR_FS_BASE, addr);
+                               ret = wrmsrl_safe(MSR_FS_BASE, addr);
                        }
                }
                put_cpu();
index 5de92f1abd76fc4d055a42af0c690284c65b7f2d..52190a938b4ac0d26a85704e6db4c131dd938aca 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <asm/virtext.h>
 #include <asm/cpu.h>
 #include <asm/nmi.h>
+#include <asm/smp.h>
 
-#ifdef CONFIG_X86_32
-# include <linux/ctype.h>
-# include <linux/mc146818rtc.h>
-# include <asm/realmode.h>
-#else
-# include <asm/x86_init.h>
-#endif
+#include <linux/ctype.h>
+#include <linux/mc146818rtc.h>
+#include <asm/realmode.h>
+#include <asm/x86_init.h>
 
 /*
  * Power off function, if any
@@ -49,7 +49,7 @@ int reboot_force;
  */
 static int reboot_default = 1;
 
-#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
+#ifdef CONFIG_SMP
 static int reboot_cpu = -1;
 #endif
 
@@ -67,8 +67,8 @@ bool port_cf9_safe = false;
  * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
  * warm   Don't set the cold reboot flag
  * cold   Set the cold reboot flag
- * bios   Reboot by jumping through the BIOS (only for X86_32)
- * smp    Reboot by executing reset on BSP or other CPU (only for X86_32)
+ * bios   Reboot by jumping through the BIOS
+ * smp    Reboot by executing reset on BSP or other CPU
  * triple Force a triple fault (init)
  * kbd    Use the keyboard controller. cold reset (default)
  * acpi   Use the RESET_REG in the FADT
@@ -95,7 +95,6 @@ static int __init reboot_setup(char *str)
                        reboot_mode = 0;
                        break;
 
-#ifdef CONFIG_X86_32
 #ifdef CONFIG_SMP
                case 's':
                        if (isdigit(*(str+1))) {
@@ -112,7 +111,6 @@ static int __init reboot_setup(char *str)
 #endif /* CONFIG_SMP */
 
                case 'b':
-#endif
                case 'a':
                case 'k':
                case 't':
@@ -138,7 +136,6 @@ static int __init reboot_setup(char *str)
 __setup("reboot=", reboot_setup);
 
 
-#ifdef CONFIG_X86_32
 /*
  * Reboot options and system auto-detection code provided by
  * Dell Inc. so their systems "just work". :-)
@@ -152,16 +149,14 @@ static int __init set_bios_reboot(const struct dmi_system_id *d)
 {
        if (reboot_type != BOOT_BIOS) {
                reboot_type = BOOT_BIOS;
-               printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
+               pr_info("%s series board detected. Selecting %s-method for reboots.\n",
+                       "BIOS", d->ident);
        }
        return 0;
 }
 
-void machine_real_restart(unsigned int type)
+void __noreturn machine_real_restart(unsigned int type)
 {
-       void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int))
-               real_mode_header->machine_real_restart_asm;
-
        local_irq_disable();
 
        /*
@@ -181,25 +176,28 @@ void machine_real_restart(unsigned int type)
        /*
         * Switch back to the initial page table.
         */
+#ifdef CONFIG_X86_32
        load_cr3(initial_page_table);
-
-       /*
-        * Write 0x1234 to absolute memory location 0x472.  The BIOS reads
-        * this on booting to tell it to "Bypass memory test (also warm
-        * boot)".  This seems like a fairly standard thing that gets set by
-        * REBOOT.COM programs, and the previous reset routine did this
-        * too. */
-       *((unsigned short *)0x472) = reboot_mode;
+#else
+       write_cr3(real_mode_header->trampoline_pgd);
+#endif
 
        /* Jump to the identity-mapped low memory code */
-       restart_lowmem(type);
+#ifdef CONFIG_X86_32
+       asm volatile("jmpl *%0" : :
+                    "rm" (real_mode_header->machine_real_restart_asm),
+                    "a" (type));
+#else
+       asm volatile("ljmpl *%0" : :
+                    "m" (real_mode_header->machine_real_restart_asm),
+                    "D" (type));
+#endif
+       unreachable();
 }
 #ifdef CONFIG_APM_MODULE
 EXPORT_SYMBOL(machine_real_restart);
 #endif
 
-#endif /* CONFIG_X86_32 */
-
 /*
  * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
  */
@@ -207,8 +205,8 @@ static int __init set_pci_reboot(const struct dmi_system_id *d)
 {
        if (reboot_type != BOOT_CF9) {
                reboot_type = BOOT_CF9;
-               printk(KERN_INFO "%s series board detected. "
-                      "Selecting PCI-method for reboots.\n", d->ident);
+               pr_info("%s series board detected. Selecting %s-method for reboots.\n",
+                       "PCI", d->ident);
        }
        return 0;
 }
@@ -217,17 +215,16 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d)
 {
        if (reboot_type != BOOT_KBD) {
                reboot_type = BOOT_KBD;
-               printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident);
+               pr_info("%s series board detected. Selecting %s-method for reboot.\n",
+                       "KBD", d->ident);
        }
        return 0;
 }
 
 /*
- * This is a single dmi_table handling all reboot quirks.  Note that
- * REBOOT_BIOS is only available for 32bit
+ * This is a single dmi_table handling all reboot quirks.
  */
 static struct dmi_system_id __initdata reboot_dmi_table[] = {
-#ifdef CONFIG_X86_32
        {       /* Handle problems with rebooting on Dell E520's */
                .callback = set_bios_reboot,
                .ident = "Dell E520",
@@ -377,7 +374,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
                        DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
                },
        },
-#endif /* CONFIG_X86_32 */
 
        {       /* Handle reboot issue on Acer Aspire one */
                .callback = set_kbd_reboot,
@@ -584,13 +580,11 @@ static void native_machine_emergency_restart(void)
                        reboot_type = BOOT_KBD;
                        break;
 
-#ifdef CONFIG_X86_32
                case BOOT_BIOS:
                        machine_real_restart(MRR_BIOS);
 
                        reboot_type = BOOT_KBD;
                        break;
-#endif
 
                case BOOT_ACPI:
                        acpi_reboot();
@@ -632,12 +626,10 @@ void native_machine_shutdown(void)
        /* The boot cpu is always logical cpu 0 */
        int reboot_cpu_id = 0;
 
-#ifdef CONFIG_X86_32
        /* See if there has been given a command line override */
        if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
                cpu_online(reboot_cpu))
                reboot_cpu_id = reboot_cpu;
-#endif
 
        /* Make certain the cpu I'm about to reboot on is online */
        if (!cpu_online(reboot_cpu_id))
@@ -678,7 +670,7 @@ static void __machine_emergency_restart(int emergency)
 
 static void native_machine_restart(char *__unused)
 {
-       printk("machine restart\n");
+       pr_notice("machine restart\n");
 
        if (!reboot_force)
                machine_shutdown();
index 16be6dc14db1b67c108475466ee494312e82d665..f4b9b80e1b95e2a9d0341fd62ed4412949b52243 100644 (file)
@@ -1031,8 +1031,6 @@ void __init setup_arch(char **cmdline_p)
 
        x86_init.timers.wallclock_init();
 
-       x86_platform.wallclock_init();
-
        mcheck_init();
 
        arch_init_ideal_nops();
index 21af737053aad05fb726a0e1023dfad428064518..b280908a376e20efc6773b76c6e80353ef8680f4 100644 (file)
@@ -6,6 +6,9 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-2002   x86-64 support by Andi Kleen
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
@@ -814,7 +817,7 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
                       me->comm, me->pid, where, frame,
                       regs->ip, regs->sp, regs->orig_ax);
                print_vma_addr(" in ", regs->ip);
-               printk(KERN_CONT "\n");
+               pr_cont("\n");
        }
 
        force_sig(SIGSEGV, me);
index 7bd8a0823654115cdb476b1693cb3eaeb6affba3..c1a310fb8309b471301330abeda28b040fca5824 100644 (file)
@@ -1,4 +1,4 @@
-/*
+ /*
  *     x86 SMP booting functions
  *
  *     (c) 1995 Alan Cox, Building #3 <alan@lxorguk.ukuu.org.uk>
@@ -39,6 +39,8 @@
  *     Glauber Costa           :       i386 and x86_64 integration
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/module.h>
@@ -184,7 +186,7 @@ static void __cpuinit smp_callin(void)
         * boards)
         */
 
-       pr_debug("CALLIN, before setup_local_APIC().\n");
+       pr_debug("CALLIN, before setup_local_APIC()\n");
        if (apic->smp_callin_clear_local_apic)
                apic->smp_callin_clear_local_apic();
        setup_local_APIC();
@@ -255,22 +257,13 @@ notrace static void __cpuinit start_secondary(void *unused)
        check_tsc_sync_target();
 
        /*
-        * We need to hold call_lock, so there is no inconsistency
-        * between the time smp_call_function() determines number of
-        * IPI recipients, and the time when the determination is made
-        * for which cpus receive the IPI. Holding this
-        * lock helps us to not include this cpu in a currently in progress
-        * smp_call_function().
-        *
         * We need to hold vector_lock so there the set of online cpus
         * does not change while we are assigning vectors to cpus.  Holding
         * this lock ensures we don't half assign or remove an irq from a cpu.
         */
-       ipi_call_lock();
        lock_vector_lock();
        set_cpu_online(smp_processor_id(), true);
        unlock_vector_lock();
-       ipi_call_unlock();
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
        x86_platform.nmi_init();
 
@@ -432,17 +425,16 @@ static void impress_friends(void)
        /*
         * Allow the user to impress friends.
         */
-       pr_debug("Before bogomips.\n");
+       pr_debug("Before bogomips\n");
        for_each_possible_cpu(cpu)
                if (cpumask_test_cpu(cpu, cpu_callout_mask))
                        bogosum += cpu_data(cpu).loops_per_jiffy;
-       printk(KERN_INFO
-               "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+       pr_info("Total of %d processors activated (%lu.%02lu BogoMIPS)\n",
                num_online_cpus(),
                bogosum/(500000/HZ),
                (bogosum/(5000/HZ))%100);
 
-       pr_debug("Before bogocount - setting activated=1.\n");
+       pr_debug("Before bogocount - setting activated=1\n");
 }
 
 void __inquire_remote_apic(int apicid)
@@ -452,18 +444,17 @@ void __inquire_remote_apic(int apicid)
        int timeout;
        u32 status;
 
-       printk(KERN_INFO "Inquiring remote APIC 0x%x...\n", apicid);
+       pr_info("Inquiring remote APIC 0x%x...\n", apicid);
 
        for (i = 0; i < ARRAY_SIZE(regs); i++) {
-               printk(KERN_INFO "... APIC 0x%x %s: ", apicid, names[i]);
+               pr_info("... APIC 0x%x %s: ", apicid, names[i]);
 
                /*
                 * Wait for idle.
                 */
                status = safe_apic_wait_icr_idle();
                if (status)
-                       printk(KERN_CONT
-                              "a previous APIC delivery may have failed\n");
+                       pr_cont("a previous APIC delivery may have failed\n");
 
                apic_icr_write(APIC_DM_REMRD | regs[i], apicid);
 
@@ -476,10 +467,10 @@ void __inquire_remote_apic(int apicid)
                switch (status) {
                case APIC_ICR_RR_VALID:
                        status = apic_read(APIC_RRR);
-                       printk(KERN_CONT "%08x\n", status);
+                       pr_cont("%08x\n", status);
                        break;
                default:
-                       printk(KERN_CONT "failed\n");
+                       pr_cont("failed\n");
                }
        }
 }
@@ -513,12 +504,12 @@ wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
                        apic_write(APIC_ESR, 0);
                accept_status = (apic_read(APIC_ESR) & 0xEF);
        }
-       pr_debug("NMI sent.\n");
+       pr_debug("NMI sent\n");
 
        if (send_status)
-               printk(KERN_ERR "APIC never delivered???\n");
+               pr_err("APIC never delivered???\n");
        if (accept_status)
-               printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
+               pr_err("APIC delivery error (%lx)\n", accept_status);
 
        return (send_status | accept_status);
 }
@@ -540,7 +531,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
                apic_read(APIC_ESR);
        }
 
-       pr_debug("Asserting INIT.\n");
+       pr_debug("Asserting INIT\n");
 
        /*
         * Turn INIT on target chip
@@ -556,7 +547,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
 
        mdelay(10);
 
-       pr_debug("Deasserting INIT.\n");
+       pr_debug("Deasserting INIT\n");
 
        /* Target chip */
        /* Send IPI */
@@ -589,14 +580,14 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
        /*
         * Run STARTUP IPI loop.
         */
-       pr_debug("#startup loops: %d.\n", num_starts);
+       pr_debug("#startup loops: %d\n", num_starts);
 
        for (j = 1; j <= num_starts; j++) {
-               pr_debug("Sending STARTUP #%d.\n", j);
+               pr_debug("Sending STARTUP #%d\n", j);
                if (maxlvt > 3)         /* Due to the Pentium erratum 3AP.  */
                        apic_write(APIC_ESR, 0);
                apic_read(APIC_ESR);
-               pr_debug("After apic_write.\n");
+               pr_debug("After apic_write\n");
 
                /*
                 * STARTUP IPI
@@ -613,7 +604,7 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
                 */
                udelay(300);
 
-               pr_debug("Startup point 1.\n");
+               pr_debug("Startup point 1\n");
 
                pr_debug("Waiting for send to finish...\n");
                send_status = safe_apic_wait_icr_idle();
@@ -628,12 +619,12 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
                if (send_status || accept_status)
                        break;
        }
-       pr_debug("After Startup.\n");
+       pr_debug("After Startup\n");
 
        if (send_status)
-               printk(KERN_ERR "APIC never delivered???\n");
+               pr_err("APIC never delivered???\n");
        if (accept_status)
-               printk(KERN_ERR "APIC delivery error (%lx).\n", accept_status);
+               pr_err("APIC delivery error (%lx)\n", accept_status);
 
        return (send_status | accept_status);
 }
@@ -647,11 +638,11 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
        if (system_state == SYSTEM_BOOTING) {
                if (node != current_node) {
                        if (current_node > (-1))
-                               pr_cont(" Ok.\n");
+                               pr_cont(" OK\n");
                        current_node = node;
                        pr_info("Booting Node %3d, Processors ", node);
                }
-               pr_cont(" #%d%s", cpu, cpu == (nr_cpu_ids - 1) ? " Ok.\n" : "");
+               pr_cont(" #%d%s", cpu, cpu == (nr_cpu_ids - 1) ? " OK\n" : "");
                return;
        } else
                pr_info("Booting Node %d Processor %d APIC 0x%x\n",
@@ -731,9 +722,9 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
                /*
                 * allow APs to start initializing.
                 */
-               pr_debug("Before Callout %d.\n", cpu);
+               pr_debug("Before Callout %d\n", cpu);
                cpumask_set_cpu(cpu, cpu_callout_mask);
-               pr_debug("After Callout %d.\n", cpu);
+               pr_debug("After Callout %d\n", cpu);
 
                /*
                 * Wait 5s total for a response
@@ -761,7 +752,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
                                pr_err("CPU%d: Stuck ??\n", cpu);
                        else
                                /* trampoline code not run */
-                               pr_err("CPU%d: Not responding.\n", cpu);
+                               pr_err("CPU%d: Not responding\n", cpu);
                        if (apic->inquire_remote_apic)
                                apic->inquire_remote_apic(apicid);
                }
@@ -806,7 +797,7 @@ int __cpuinit native_cpu_up(unsigned int cpu, struct task_struct *tidle)
        if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
            !physid_isset(apicid, phys_cpu_present_map) ||
            !apic->apic_id_valid(apicid)) {
-               printk(KERN_ERR "%s: bad cpu %d\n", __func__, cpu);
+               pr_err("%s: bad cpu %d\n", __func__, cpu);
                return -EINVAL;
        }
 
@@ -887,9 +878,8 @@ static int __init smp_sanity_check(unsigned max_cpus)
                unsigned int cpu;
                unsigned nr;
 
-               printk(KERN_WARNING
-                      "More than 8 CPUs detected - skipping them.\n"
-                      "Use CONFIG_X86_BIGSMP.\n");
+               pr_warn("More than 8 CPUs detected - skipping them\n"
+                       "Use CONFIG_X86_BIGSMP\n");
 
                nr = 0;
                for_each_present_cpu(cpu) {
@@ -910,8 +900,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
 #endif
 
        if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
-               printk(KERN_WARNING
-                       "weird, boot CPU (#%d) not listed by the BIOS.\n",
+               pr_warn("weird, boot CPU (#%d) not listed by the BIOS\n",
                        hard_smp_processor_id());
 
                physid_set(hard_smp_processor_id(), phys_cpu_present_map);
@@ -923,11 +912,10 @@ static int __init smp_sanity_check(unsigned max_cpus)
         */
        if (!smp_found_config && !acpi_lapic) {
                preempt_enable();
-               printk(KERN_NOTICE "SMP motherboard not detected.\n");
+               pr_notice("SMP motherboard not detected\n");
                disable_smp();
                if (APIC_init_uniprocessor())
-                       printk(KERN_NOTICE "Local APIC not detected."
-                                          " Using dummy APIC emulation.\n");
+                       pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
                return -1;
        }
 
@@ -936,9 +924,8 @@ static int __init smp_sanity_check(unsigned max_cpus)
         * CPU too, but we do it for the sake of robustness anyway.
         */
        if (!apic->check_phys_apicid_present(boot_cpu_physical_apicid)) {
-               printk(KERN_NOTICE
-                       "weird, boot CPU (#%d) not listed by the BIOS.\n",
-                       boot_cpu_physical_apicid);
+               pr_notice("weird, boot CPU (#%d) not listed by the BIOS\n",
+                         boot_cpu_physical_apicid);
                physid_set(hard_smp_processor_id(), phys_cpu_present_map);
        }
        preempt_enable();
@@ -951,8 +938,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
                if (!disable_apic) {
                        pr_err("BIOS bug, local APIC #%d not detected!...\n",
                                boot_cpu_physical_apicid);
-                       pr_err("... forcing use of dummy APIC emulation."
-                               "(tell your hw vendor)\n");
+                       pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n");
                }
                smpboot_clear_io_apic();
                disable_ioapic_support();
@@ -965,7 +951,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
         * If SMP should be disabled, then really disable it!
         */
        if (!max_cpus) {
-               printk(KERN_INFO "SMP mode deactivated.\n");
+               pr_info("SMP mode deactivated\n");
                smpboot_clear_io_apic();
 
                connect_bsp_APIC();
@@ -1017,7 +1003,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 
 
        if (smp_sanity_check(max_cpus) < 0) {
-               printk(KERN_INFO "SMP disabled\n");
+               pr_info("SMP disabled\n");
                disable_smp();
                goto out;
        }
@@ -1055,7 +1041,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
         * Set up local APIC timer on boot CPU.
         */
 
-       printk(KERN_INFO "CPU%d: ", 0);
+       pr_info("CPU%d: ", 0);
        print_cpu_info(&cpu_data(0));
        x86_init.timers.setup_percpu_clockev();
 
@@ -1105,7 +1091,7 @@ void __init native_smp_prepare_boot_cpu(void)
 
 void __init native_smp_cpus_done(unsigned int max_cpus)
 {
-       pr_debug("Boot done.\n");
+       pr_debug("Boot done\n");
 
        nmi_selftest();
        impress_friends();
@@ -1166,8 +1152,7 @@ __init void prefill_possible_map(void)
 
        /* nr_cpu_ids could be reduced via nr_cpus= */
        if (possible > nr_cpu_ids) {
-               printk(KERN_WARNING
-                       "%d Processors exceeds NR_CPUS limit of %d\n",
+               pr_warn("%d Processors exceeds NR_CPUS limit of %d\n",
                        possible, nr_cpu_ids);
                possible = nr_cpu_ids;
        }
@@ -1176,13 +1161,12 @@ __init void prefill_possible_map(void)
        if (!setup_max_cpus)
 #endif
        if (possible > i) {
-               printk(KERN_WARNING
-                       "%d Processors exceeds max_cpus limit of %u\n",
+               pr_warn("%d Processors exceeds max_cpus limit of %u\n",
                        possible, setup_max_cpus);
                possible = i;
        }
 
-       printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
+       pr_info("Allowing %d CPUs, %d hotplug CPUs\n",
                possible, max_t(int, possible - num_processors, 0));
 
        for (i = 0; i < possible; i++)
index 05b31d92f69cdf7b7e9ccc22c82835a5e6286bbc..b481341c9369da649908b57c3e8c39b1586b0111 100644 (file)
@@ -9,6 +9,9 @@
 /*
  * Handle hardware traps and faults.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/interrupt.h>
 #include <linux/kallsyms.h>
 #include <linux/spinlock.h>
@@ -143,12 +146,11 @@ trap_signal:
 #ifdef CONFIG_X86_64
        if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
            printk_ratelimit()) {
-               printk(KERN_INFO
-                      "%s[%d] trap %s ip:%lx sp:%lx error:%lx",
-                      tsk->comm, tsk->pid, str,
-                      regs->ip, regs->sp, error_code);
+               pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx",
+                       tsk->comm, tsk->pid, str,
+                       regs->ip, regs->sp, error_code);
                print_vma_addr(" in ", regs->ip);
-               printk("\n");
+               pr_cont("\n");
        }
 #endif
 
@@ -269,12 +271,11 @@ do_general_protection(struct pt_regs *regs, long error_code)
 
        if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
                        printk_ratelimit()) {
-               printk(KERN_INFO
-                       "%s[%d] general protection ip:%lx sp:%lx error:%lx",
+               pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx",
                        tsk->comm, task_pid_nr(tsk),
                        regs->ip, regs->sp, error_code);
                print_vma_addr(" in ", regs->ip);
-               printk("\n");
+               pr_cont("\n");
        }
 
        force_sig(SIGSEGV, tsk);
@@ -570,7 +571,7 @@ do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
        conditional_sti(regs);
 #if 0
        /* No need to warn about this any longer. */
-       printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+       pr_info("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
 }
 
index fc0a147e372726fb019b8873969dc1fca3e43109..cfa5d4f7ca56c06934c8b8bfa6e9815fe8e606b4 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -84,8 +86,7 @@ EXPORT_SYMBOL_GPL(check_tsc_unstable);
 #ifdef CONFIG_X86_TSC
 int __init notsc_setup(char *str)
 {
-       printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
-                       "cannot disable TSC completely.\n");
+       pr_warn("Kernel compiled with CONFIG_X86_TSC, cannot disable TSC completely\n");
        tsc_disabled = 1;
        return 1;
 }
@@ -373,7 +374,7 @@ static unsigned long quick_pit_calibrate(void)
                        goto success;
                }
        }
-       printk("Fast TSC calibration failed\n");
+       pr_err("Fast TSC calibration failed\n");
        return 0;
 
 success:
@@ -392,7 +393,7 @@ success:
         */
        delta *= PIT_TICK_RATE;
        do_div(delta, i*256*1000);
-       printk("Fast TSC calibration using PIT\n");
+       pr_info("Fast TSC calibration using PIT\n");
        return delta;
 }
 
@@ -487,9 +488,8 @@ unsigned long native_calibrate_tsc(void)
                 * use the reference value, as it is more precise.
                 */
                if (delta >= 90 && delta <= 110) {
-                       printk(KERN_INFO
-                              "TSC: PIT calibration matches %s. %d loops\n",
-                              hpet ? "HPET" : "PMTIMER", i + 1);
+                       pr_info("PIT calibration matches %s. %d loops\n",
+                               hpet ? "HPET" : "PMTIMER", i + 1);
                        return tsc_ref_min;
                }
 
@@ -511,38 +511,36 @@ unsigned long native_calibrate_tsc(void)
         */
        if (tsc_pit_min == ULONG_MAX) {
                /* PIT gave no useful value */
-               printk(KERN_WARNING "TSC: Unable to calibrate against PIT\n");
+               pr_warn("Unable to calibrate against PIT\n");
 
                /* We don't have an alternative source, disable TSC */
                if (!hpet && !ref1 && !ref2) {
-                       printk("TSC: No reference (HPET/PMTIMER) available\n");
+                       pr_notice("No reference (HPET/PMTIMER) available\n");
                        return 0;
                }
 
                /* The alternative source failed as well, disable TSC */
                if (tsc_ref_min == ULONG_MAX) {
-                       printk(KERN_WARNING "TSC: HPET/PMTIMER calibration "
-                              "failed.\n");
+                       pr_warn("HPET/PMTIMER calibration failed\n");
                        return 0;
                }
 
                /* Use the alternative source */
-               printk(KERN_INFO "TSC: using %s reference calibration\n",
-                      hpet ? "HPET" : "PMTIMER");
+               pr_info("using %s reference calibration\n",
+                       hpet ? "HPET" : "PMTIMER");
 
                return tsc_ref_min;
        }
 
        /* We don't have an alternative source, use the PIT calibration value */
        if (!hpet && !ref1 && !ref2) {
-               printk(KERN_INFO "TSC: Using PIT calibration value\n");
+               pr_info("Using PIT calibration value\n");
                return tsc_pit_min;
        }
 
        /* The alternative source failed, use the PIT calibration value */
        if (tsc_ref_min == ULONG_MAX) {
-               printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed. "
-                      "Using PIT calibration\n");
+               pr_warn("HPET/PMTIMER calibration failed. Using PIT calibration.\n");
                return tsc_pit_min;
        }
 
@@ -551,9 +549,9 @@ unsigned long native_calibrate_tsc(void)
         * the PIT value as we know that there are PMTIMERs around
         * running at double speed. At least we let the user know:
         */
-       printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n",
-              hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
-       printk(KERN_INFO "TSC: Using PIT calibration value\n");
+       pr_warn("PIT calibration deviates from %s: %lu %lu\n",
+               hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min);
+       pr_info("Using PIT calibration value\n");
        return tsc_pit_min;
 }
 
@@ -785,7 +783,7 @@ void mark_tsc_unstable(char *reason)
                tsc_unstable = 1;
                sched_clock_stable = 0;
                disable_sched_clock_irqtime();
-               printk(KERN_INFO "Marking TSC unstable due to %s\n", reason);
+               pr_info("Marking TSC unstable due to %s\n", reason);
                /* Change only the rating, when not registered */
                if (clocksource_tsc.mult)
                        clocksource_mark_unstable(&clocksource_tsc);
@@ -912,9 +910,9 @@ static void tsc_refine_calibration_work(struct work_struct *work)
                goto out;
 
        tsc_khz = freq;
-       printk(KERN_INFO "Refined TSC clocksource calibration: "
-               "%lu.%03lu MHz.\n", (unsigned long)tsc_khz / 1000,
-                                       (unsigned long)tsc_khz % 1000);
+       pr_info("Refined TSC clocksource calibration: %lu.%03lu MHz\n",
+               (unsigned long)tsc_khz / 1000,
+               (unsigned long)tsc_khz % 1000);
 
 out:
        clocksource_register_khz(&clocksource_tsc, tsc_khz);
@@ -970,9 +968,9 @@ void __init tsc_init(void)
                return;
        }
 
-       printk("Detected %lu.%03lu MHz processor.\n",
-                       (unsigned long)cpu_khz / 1000,
-                       (unsigned long)cpu_khz % 1000);
+       pr_info("Detected %lu.%03lu MHz processor\n",
+               (unsigned long)cpu_khz / 1000,
+               (unsigned long)cpu_khz % 1000);
 
        /*
         * Secondary CPUs do not run through tsc_init(), so set up
index dc4e910a7d964c76dd4935c2986c33e37b1a595b..36fd42091fa7283d71e189ddb55cf29a5e940790 100644 (file)
@@ -409,9 +409,10 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm,
  * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
  * @mm: the probed address space.
  * @arch_uprobe: the probepoint information.
+ * @addr: virtual address at which to install the probepoint
  * Return 0 on success or a -ve number on error.
  */
-int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm)
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr)
 {
        int ret;
        struct insn insn;
index 255f58ae71e8991838080eac595786a60f372a62..54abcc0baf23f0f4181106a7b2a83312c01ed03f 100644 (file)
@@ -28,6 +28,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
@@ -137,14 +139,14 @@ struct pt_regs *save_v86_state(struct kernel_vm86_regs *regs)
        local_irq_enable();
 
        if (!current->thread.vm86_info) {
-               printk("no vm86_info: BAD\n");
+               pr_alert("no vm86_info: BAD\n");
                do_exit(SIGSEGV);
        }
        set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | current->thread.v86mask);
        tmp = copy_vm86_regs_to_user(&current->thread.vm86_info->regs, regs);
        tmp += put_user(current->thread.screen_bitmap, &current->thread.vm86_info->screen_bitmap);
        if (tmp) {
-               printk("vm86: could not access userspace vm86_info\n");
+               pr_alert("could not access userspace vm86_info\n");
                do_exit(SIGSEGV);
        }
 
index 8eeb55a551b423fdce43eb432c8f8f5599246848..992f890283e9260980349ff128f33446f339810a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pci_ids.h>
 #include <linux/pci_regs.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/apic.h>
 #include <asm/pci-direct.h>
@@ -95,6 +96,18 @@ static void __init set_vsmp_pv_ops(void)
        ctl = readl(address + 4);
        printk(KERN_INFO "vSMP CTL: capabilities:0x%08x  control:0x%08x\n",
               cap, ctl);
+
+       /* If possible, let the vSMP foundation route the interrupt optimally */
+#ifdef CONFIG_SMP
+       if (cap & ctl & BIT(8)) {
+               ctl &= ~BIT(8);
+#ifdef CONFIG_PROC_FS
+               /* Don't let users change irq affinity via procfs */
+               no_irq_affinity = 1;
+#endif
+       }
+#endif
+
        if (cap & ctl & (1 << 4)) {
                /* Setup irq ops and turn on vSMP  IRQ fastpath handling */
                pv_irq_ops.irq_disable = PV_CALLEE_SAVE(vsmp_irq_disable);
@@ -102,12 +115,11 @@ static void __init set_vsmp_pv_ops(void)
                pv_irq_ops.save_fl  = PV_CALLEE_SAVE(vsmp_save_fl);
                pv_irq_ops.restore_fl  = PV_CALLEE_SAVE(vsmp_restore_fl);
                pv_init_ops.patch = vsmp_patch;
-
                ctl &= ~(1 << 4);
-               writel(ctl, address + 4);
-               ctl = readl(address + 4);
-               printk(KERN_INFO "vSMP CTL: control set to:0x%08x\n", ctl);
        }
+       writel(ctl, address + 4);
+       ctl = readl(address + 4);
+       pr_info("vSMP CTL: control set to:0x%08x\n", ctl);
 
        early_iounmap(address, 8);
 }
@@ -187,12 +199,36 @@ static void __init vsmp_cap_cpus(void)
 #endif
 }
 
+static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
+{
+       return hard_smp_processor_id() >> index_msb;
+}
+
+/*
+ * In vSMP, all cpus should be capable of handling interrupts, regardless of
+ * the APIC used.
+ */
+static void fill_vector_allocation_domain(int cpu, struct cpumask *retmask,
+                                         const struct cpumask *mask)
+{
+       cpumask_setall(retmask);
+}
+
+static void vsmp_apic_post_init(void)
+{
+       /* need to update phys_pkg_id */
+       apic->phys_pkg_id = apicid_phys_pkg_id;
+       apic->vector_allocation_domain = fill_vector_allocation_domain;
+}
+
 void __init vsmp_init(void)
 {
        detect_vsmp_box();
        if (!is_vsmp_box())
                return;
 
+       x86_platform.apic_post_init = vsmp_apic_post_init;
+
        vsmp_cap_cpus();
 
        set_vsmp_pv_ops();
index 7515cf0e1805eae308e1dd0650b1dd33a8d8564d..8d141b30904657871358a4fb8deb927c7a022257 100644 (file)
@@ -18,6 +18,8 @@
  *  use the vDSO.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -111,18 +113,13 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
 static void warn_bad_vsyscall(const char *level, struct pt_regs *regs,
                              const char *message)
 {
-       static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
-       struct task_struct *tsk;
-
-       if (!show_unhandled_signals || !__ratelimit(&rs))
+       if (!show_unhandled_signals)
                return;
 
-       tsk = current;
-
-       printk("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
-              level, tsk->comm, task_pid_nr(tsk),
-              message, regs->ip, regs->cs,
-              regs->sp, regs->ax, regs->si, regs->di);
+       pr_notice_ratelimited("%s%s[%d] %s ip:%lx cs:%lx sp:%lx ax:%lx si:%lx di:%lx\n",
+                             level, current->comm, task_pid_nr(current),
+                             message, regs->ip, regs->cs,
+                             regs->sp, regs->ax, regs->si, regs->di);
 }
 
 static int addr_to_vsyscall_nr(unsigned long addr)
@@ -139,6 +136,19 @@ static int addr_to_vsyscall_nr(unsigned long addr)
        return nr;
 }
 
+#ifdef CONFIG_SECCOMP
+static int vsyscall_seccomp(struct task_struct *tsk, int syscall_nr)
+{
+       if (!seccomp_mode(&tsk->seccomp))
+               return 0;
+       task_pt_regs(tsk)->orig_ax = syscall_nr;
+       task_pt_regs(tsk)->ax = syscall_nr;
+       return __secure_computing(syscall_nr);
+}
+#else
+#define vsyscall_seccomp(_tsk, _nr) 0
+#endif
+
 static bool write_ok_or_segv(unsigned long ptr, size_t size)
 {
        /*
@@ -174,6 +184,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
        int vsyscall_nr;
        int prev_sig_on_uaccess_error;
        long ret;
+       int skip;
 
        /*
         * No point in checking CS -- the only way to get here is a user mode
@@ -205,9 +216,6 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
        }
 
        tsk = current;
-       if (seccomp_mode(&tsk->seccomp))
-               do_exit(SIGKILL);
-
        /*
         * With a real vsyscall, page faults cause SIGSEGV.  We want to
         * preserve that behavior to make writing exploits harder.
@@ -222,8 +230,13 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
         * address 0".
         */
        ret = -EFAULT;
+       skip = 0;
        switch (vsyscall_nr) {
        case 0:
+               skip = vsyscall_seccomp(tsk, __NR_gettimeofday);
+               if (skip)
+                       break;
+
                if (!write_ok_or_segv(regs->di, sizeof(struct timeval)) ||
                    !write_ok_or_segv(regs->si, sizeof(struct timezone)))
                        break;
@@ -234,6 +247,10 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
                break;
 
        case 1:
+               skip = vsyscall_seccomp(tsk, __NR_time);
+               if (skip)
+                       break;
+
                if (!write_ok_or_segv(regs->di, sizeof(time_t)))
                        break;
 
@@ -241,6 +258,10 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
                break;
 
        case 2:
+               skip = vsyscall_seccomp(tsk, __NR_getcpu);
+               if (skip)
+                       break;
+
                if (!write_ok_or_segv(regs->di, sizeof(unsigned)) ||
                    !write_ok_or_segv(regs->si, sizeof(unsigned)))
                        break;
@@ -253,6 +274,12 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 
        current_thread_info()->sig_on_uaccess_error = prev_sig_on_uaccess_error;
 
+       if (skip) {
+               if ((long)regs->ax <= 0L) /* seccomp errno emulation */
+                       goto do_ret;
+               goto done; /* seccomp trace/trap */
+       }
+
        if (ret == -EFAULT) {
                /* Bad news -- userspace fed a bad pointer to a vsyscall. */
                warn_bad_vsyscall(KERN_INFO, regs,
@@ -271,10 +298,11 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
 
        regs->ax = ret;
 
+do_ret:
        /* Emulate a ret instruction. */
        regs->ip = caller;
        regs->sp += 8;
-
+done:
        return true;
 
 sigsegv:
index 9796c2f3d0745e8b73b690fff13f7529b5792507..6020f6f5927cbc1035b7f86b1f19f1422ded0acf 100644 (file)
@@ -28,6 +28,7 @@ EXPORT_SYMBOL(__put_user_8);
 
 EXPORT_SYMBOL(copy_user_generic_string);
 EXPORT_SYMBOL(copy_user_generic_unrolled);
+EXPORT_SYMBOL(copy_user_enhanced_fast_string);
 EXPORT_SYMBOL(__copy_user_nocache);
 EXPORT_SYMBOL(_copy_from_user);
 EXPORT_SYMBOL(_copy_to_user);
index 35c5e543f55023f32b1316e08ce0d405e671e095..9f3167e891ef4af9f92c57ac8092790412906ee3 100644 (file)
@@ -29,7 +29,6 @@ void __init x86_init_uint_noop(unsigned int unused) { }
 void __init x86_init_pgd_noop(pgd_t *unused) { }
 int __init iommu_init_noop(void) { return 0; }
 void iommu_shutdown_noop(void) { }
-void wallclock_init_noop(void) { }
 
 /*
  * The platform setup functions are preset with the default functions
@@ -101,7 +100,6 @@ static int default_i8042_detect(void) { return 1; };
 
 struct x86_platform_ops x86_platform = {
        .calibrate_tsc                  = native_calibrate_tsc,
-       .wallclock_init                 = wallclock_init_noop,
        .get_wallclock                  = mach_get_cmos_time,
        .set_wallclock                  = mach_set_rtc_mmss,
        .iommu_shutdown                 = iommu_shutdown_noop,
index bd18149b2b0f09532870075a274ff1576b5de1d7..3d3e2070911971eb8aa3625e2708b2de34852f1d 100644 (file)
@@ -3,6 +3,9 @@
  *
  * Author: Suresh Siddha <suresh.b.siddha@intel.com>
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bootmem.h>
 #include <linux/compat.h>
 #include <asm/i387.h>
@@ -162,7 +165,7 @@ int save_i387_xstate(void __user *buf)
        BUG_ON(sig_xstate_size < xstate_size);
 
        if ((unsigned long)buf % 64)
-               printk("save_i387_xstate: bad fpstate %p\n", buf);
+               pr_err("%s: bad fpstate %p\n", __func__, buf);
 
        if (!used_math())
                return 0;
@@ -422,7 +425,7 @@ static void __init xstate_enable_boot_cpu(void)
        pcntxt_mask = eax + ((u64)edx << 32);
 
        if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
-               printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
+               pr_err("FP/SSE not shown under xsave features 0x%llx\n",
                       pcntxt_mask);
                BUG();
        }
@@ -445,9 +448,8 @@ static void __init xstate_enable_boot_cpu(void)
 
        setup_xstate_init();
 
-       printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
-              "cntxt size 0x%x\n",
-              pcntxt_mask, xstate_size);
+       pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
+               pcntxt_mask, xstate_size);
 }
 
 /*
index be3cea4407ffad63824c068332079baf16336012..57e168e27b5b865e187d5ee3d34413189a1c5905 100644 (file)
@@ -3934,6 +3934,9 @@ static void kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
 {
        struct kvm_mmu_page *page;
 
+       if (list_empty(&kvm->arch.active_mmu_pages))
+               return;
+
        page = container_of(kvm->arch.active_mmu_pages.prev,
                            struct kvm_mmu_page, link);
        kvm_mmu_prepare_zap_page(kvm, page, invalid_list);
index 2e88438ffd83186c0d7a6b136cc97ae5c943ae4a..9b7ec1150ab01ad1390217cc04176d255c5d8382 100644 (file)
@@ -80,10 +80,10 @@ static inline struct kvm_pmc *get_fixed_pmc_idx(struct kvm_pmu *pmu, int idx)
 
 static struct kvm_pmc *global_idx_to_pmc(struct kvm_pmu *pmu, int idx)
 {
-       if (idx < X86_PMC_IDX_FIXED)
+       if (idx < INTEL_PMC_IDX_FIXED)
                return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + idx, MSR_P6_EVNTSEL0);
        else
-               return get_fixed_pmc_idx(pmu, idx - X86_PMC_IDX_FIXED);
+               return get_fixed_pmc_idx(pmu, idx - INTEL_PMC_IDX_FIXED);
 }
 
 void kvm_deliver_pmi(struct kvm_vcpu *vcpu)
@@ -291,7 +291,7 @@ static void reprogram_idx(struct kvm_pmu *pmu, int idx)
        if (pmc_is_gp(pmc))
                reprogram_gp_counter(pmc, pmc->eventsel);
        else {
-               int fidx = idx - X86_PMC_IDX_FIXED;
+               int fidx = idx - INTEL_PMC_IDX_FIXED;
                reprogram_fixed_counter(pmc,
                                fixed_en_pmi(pmu->fixed_ctr_ctrl, fidx), fidx);
        }
@@ -452,7 +452,7 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu)
                return;
 
        pmu->nr_arch_gp_counters = min((int)(entry->eax >> 8) & 0xff,
-                       X86_PMC_MAX_GENERIC);
+                       INTEL_PMC_MAX_GENERIC);
        pmu->counter_bitmask[KVM_PMC_GP] =
                ((u64)1 << ((entry->eax >> 16) & 0xff)) - 1;
        bitmap_len = (entry->eax >> 24) & 0xff;
@@ -462,13 +462,13 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu)
                pmu->nr_arch_fixed_counters = 0;
        } else {
                pmu->nr_arch_fixed_counters = min((int)(entry->edx & 0x1f),
-                               X86_PMC_MAX_FIXED);
+                               INTEL_PMC_MAX_FIXED);
                pmu->counter_bitmask[KVM_PMC_FIXED] =
                        ((u64)1 << ((entry->edx >> 5) & 0xff)) - 1;
        }
 
        pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
-               (((1ull << pmu->nr_arch_fixed_counters) - 1) << X86_PMC_IDX_FIXED);
+               (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
        pmu->global_ctrl_mask = ~pmu->global_ctrl;
 }
 
@@ -478,15 +478,15 @@ void kvm_pmu_init(struct kvm_vcpu *vcpu)
        struct kvm_pmu *pmu = &vcpu->arch.pmu;
 
        memset(pmu, 0, sizeof(*pmu));
-       for (i = 0; i < X86_PMC_MAX_GENERIC; i++) {
+       for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
                pmu->gp_counters[i].type = KVM_PMC_GP;
                pmu->gp_counters[i].vcpu = vcpu;
                pmu->gp_counters[i].idx = i;
        }
-       for (i = 0; i < X86_PMC_MAX_FIXED; i++) {
+       for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) {
                pmu->fixed_counters[i].type = KVM_PMC_FIXED;
                pmu->fixed_counters[i].vcpu = vcpu;
-               pmu->fixed_counters[i].idx = i + X86_PMC_IDX_FIXED;
+               pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED;
        }
        init_irq_work(&pmu->irq_work, trigger_pmi);
        kvm_pmu_cpuid_update(vcpu);
@@ -498,13 +498,13 @@ void kvm_pmu_reset(struct kvm_vcpu *vcpu)
        int i;
 
        irq_work_sync(&pmu->irq_work);
-       for (i = 0; i < X86_PMC_MAX_GENERIC; i++) {
+       for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) {
                struct kvm_pmc *pmc = &pmu->gp_counters[i];
                stop_counter(pmc);
                pmc->counter = pmc->eventsel = 0;
        }
 
-       for (i = 0; i < X86_PMC_MAX_FIXED; i++)
+       for (i = 0; i < INTEL_PMC_MAX_FIXED; i++)
                stop_counter(&pmu->fixed_counters[i]);
 
        pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status =
index 911d2641f14c5cba355abc25e00f38f07ced1df9..62d02e3c3ed625ec6d0a5f89ceb325ee1eab7236 100644 (file)
@@ -710,16 +710,6 @@ TRACE_EVENT(kvm_skinit,
                  __entry->rip, __entry->slb)
 );
 
-#define __print_insn(insn, ilen) ({                             \
-       int i;                                                   \
-       const char *ret = p->buffer + p->len;                    \
-                                                                \
-       for (i = 0; i < ilen; ++i)                               \
-               trace_seq_printf(p, " %02x", insn[i]);           \
-       trace_seq_printf(p, "%c", 0);                            \
-       ret;                                                     \
-       })
-
 #define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
 #define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
 #define KVM_EMUL_INSN_F_CS_D   (1 << 2)
@@ -786,7 +776,7 @@ TRACE_EVENT(kvm_emulate_insn,
 
        TP_printk("%x:%llx:%s (%s)%s",
                  __entry->csbase, __entry->rip,
-                 __print_insn(__entry->insn, __entry->len),
+                 __print_hex(__entry->insn, __entry->len),
                  __print_symbolic(__entry->flags,
                                   kvm_trace_symbol_emul_flags),
                  __entry->failed ? " failed" : ""
index a311cc59b65d9769e05af4e566f6c997b3139bc4..8d6ef78b5d01c3a180959bd54f7da26ddf325188 100644 (file)
@@ -1,5 +1,5 @@
 #include <linux/module.h>
 #include <asm/msr.h>
 
-EXPORT_SYMBOL(native_rdmsr_safe_regs);
-EXPORT_SYMBOL(native_wrmsr_safe_regs);
+EXPORT_SYMBOL(rdmsr_safe_regs);
+EXPORT_SYMBOL(wrmsr_safe_regs);
index 69fa10623f2181b23740bdf0a4ad5f7919120809..f6d13eefad1063d5e525dbc0cfff1ccc12b34bc9 100644 (file)
@@ -6,13 +6,13 @@
 
 #ifdef CONFIG_X86_64
 /*
- * int native_{rdmsr,wrmsr}_safe_regs(u32 gprs[8]);
+ * int {rdmsr,wrmsr}_safe_regs(u32 gprs[8]);
  *
  * reg layout: u32 gprs[eax, ecx, edx, ebx, esp, ebp, esi, edi]
  *
  */
 .macro op_safe_regs op
-ENTRY(native_\op\()_safe_regs)
+ENTRY(\op\()_safe_regs)
        CFI_STARTPROC
        pushq_cfi %rbx
        pushq_cfi %rbp
@@ -45,13 +45,13 @@ ENTRY(native_\op\()_safe_regs)
 
        _ASM_EXTABLE(1b, 3b)
        CFI_ENDPROC
-ENDPROC(native_\op\()_safe_regs)
+ENDPROC(\op\()_safe_regs)
 .endm
 
 #else /* X86_32 */
 
 .macro op_safe_regs op
-ENTRY(native_\op\()_safe_regs)
+ENTRY(\op\()_safe_regs)
        CFI_STARTPROC
        pushl_cfi %ebx
        pushl_cfi %ebp
@@ -92,7 +92,7 @@ ENTRY(native_\op\()_safe_regs)
 
        _ASM_EXTABLE(1b, 3b)
        CFI_ENDPROC
-ENDPROC(native_\op\()_safe_regs)
+ENDPROC(\op\()_safe_regs)
 .endm
 
 #endif
index bc4e9d84157fc0c9aa85e71837998da166c1fa57..e0e6990723e982e12f425f2fdd26113725f2d52a 100644 (file)
@@ -385,7 +385,7 @@ void free_initmem(void)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
+void __init free_initrd_mem(unsigned long start, unsigned long end)
 {
        /*
         * end could be not aligned, and We can not align that,
index 303f0863782637ba3a1099397d796355f79982ff..b2b94438ff05cb3da0289f3b8800acfb77808f66 100644 (file)
@@ -312,7 +312,7 @@ static int op_amd_fill_in_addresses(struct op_msrs * const msrs)
                        goto fail;
                }
                /* both registers must be reserved */
-               if (num_counters == AMD64_NUM_COUNTERS_F15H) {
+               if (num_counters == AMD64_NUM_COUNTERS_CORE) {
                        msrs->counters[i].addr = MSR_F15H_PERF_CTR + (i << 1);
                        msrs->controls[i].addr = MSR_F15H_PERF_CTL + (i << 1);
                } else {
@@ -514,7 +514,7 @@ static int op_amd_init(struct oprofile_operations *ops)
        ops->create_files = setup_ibs_files;
 
        if (boot_cpu_data.x86 == 0x15) {
-               num_counters = AMD64_NUM_COUNTERS_F15H;
+               num_counters = AMD64_NUM_COUNTERS_CORE;
        } else {
                num_counters = AMD64_NUM_COUNTERS;
        }
index 23e5b9d7977b6e528821682f2278289c73a534a2..599be499fdf7a8aff278e7e7f16ca9593fde8c41 100644 (file)
@@ -203,7 +203,7 @@ static int xo15_sci_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int xo15_sci_resume(struct acpi_device *device)
+static int xo15_sci_resume(struct device *dev)
 {
        /* Enable all EC events */
        olpc_ec_mask_write(EC_SCI_SRC_ALL);
@@ -215,6 +215,8 @@ static int xo15_sci_resume(struct acpi_device *device)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(xo15_sci_pm, NULL, xo15_sci_resume);
+
 static const struct acpi_device_id xo15_sci_device_ids[] = {
        {"XO15EC", 0},
        {"", 0},
@@ -227,8 +229,8 @@ static struct acpi_driver xo15_sci_drv = {
        .ops = {
                .add = xo15_sci_add,
                .remove = xo15_sci_remove,
-               .resume = xo15_sci_resume,
        },
+       .drv.pm = &xo15_sci_pm,
 };
 
 static int __init xo15_sci_init(void)
index 59880afa851fc37d6995e3fd665fca1f1d3d91b3..71b5d5a07d7bbd7c26a5f9ae99cf5f0e8cacacbf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     SGI UltraViolet TLB flush routines.
  *
- *     (c) 2008-2011 Cliff Wickman <cpw@sgi.com>, SGI.
+ *     (c) 2008-2012 Cliff Wickman <cpw@sgi.com>, SGI.
  *
  *     This code is released under the GNU General Public License version 2 or
  *     later.
@@ -38,8 +38,7 @@ static int timeout_base_ns[] = {
 
 static int timeout_us;
 static int nobau;
-static int baudisabled;
-static spinlock_t disable_lock;
+static int nobau_perm;
 static cycles_t congested_cycles;
 
 /* tunables: */
@@ -47,12 +46,13 @@ static int max_concurr              = MAX_BAU_CONCURRENT;
 static int max_concurr_const   = MAX_BAU_CONCURRENT;
 static int plugged_delay       = PLUGGED_DELAY;
 static int plugsb4reset                = PLUGSB4RESET;
+static int giveup_limit                = GIVEUP_LIMIT;
 static int timeoutsb4reset     = TIMEOUTSB4RESET;
 static int ipi_reset_limit     = IPI_RESET_LIMIT;
 static int complete_threshold  = COMPLETE_THRESHOLD;
 static int congested_respns_us = CONGESTED_RESPONSE_US;
 static int congested_reps      = CONGESTED_REPS;
-static int congested_period    = CONGESTED_PERIOD;
+static int disabled_period     = DISABLED_PERIOD;
 
 static struct tunables tunables[] = {
        {&max_concurr, MAX_BAU_CONCURRENT}, /* must be [0] */
@@ -63,7 +63,8 @@ static struct tunables tunables[] = {
        {&complete_threshold, COMPLETE_THRESHOLD},
        {&congested_respns_us, CONGESTED_RESPONSE_US},
        {&congested_reps, CONGESTED_REPS},
-       {&congested_period, CONGESTED_PERIOD}
+       {&disabled_period, DISABLED_PERIOD},
+       {&giveup_limit, GIVEUP_LIMIT}
 };
 
 static struct dentry *tunables_dir;
@@ -120,6 +121,40 @@ static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
 static DEFINE_PER_CPU(struct bau_control, bau_control);
 static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask);
 
+static void
+set_bau_on(void)
+{
+       int cpu;
+       struct bau_control *bcp;
+
+       if (nobau_perm) {
+               pr_info("BAU not initialized; cannot be turned on\n");
+               return;
+       }
+       nobau = 0;
+       for_each_present_cpu(cpu) {
+               bcp = &per_cpu(bau_control, cpu);
+               bcp->nobau = 0;
+       }
+       pr_info("BAU turned on\n");
+       return;
+}
+
+static void
+set_bau_off(void)
+{
+       int cpu;
+       struct bau_control *bcp;
+
+       nobau = 1;
+       for_each_present_cpu(cpu) {
+               bcp = &per_cpu(bau_control, cpu);
+               bcp->nobau = 1;
+       }
+       pr_info("BAU turned off\n");
+       return;
+}
+
 /*
  * Determine the first node on a uvhub. 'Nodes' are used for kernel
  * memory allocation.
@@ -278,7 +313,7 @@ static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp,
                 * Both sockets dump their completed count total into
                 * the message's count.
                 */
-               smaster->socket_acknowledge_count[mdp->msg_slot] = 0;
+               *sp = 0;
                asp = (struct atomic_short *)&msg->acknowledge_count;
                msg_ack_count = atom_asr(socket_ack_count, asp);
 
@@ -491,16 +526,15 @@ static int uv1_wait_completion(struct bau_desc *bau_desc,
 }
 
 /*
- * UV2 has an extra bit of status in the ACTIVATION_STATUS_2 register.
+ * UV2 could have an extra bit of status in the ACTIVATION_STATUS_2 register.
+ * But not currently used.
  */
 static unsigned long uv2_read_status(unsigned long offset, int rshft, int desc)
 {
        unsigned long descriptor_status;
-       unsigned long descriptor_status2;
 
-       descriptor_status = ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK);
-       descriptor_status2 = (read_mmr_uv2_status() >> desc) & 0x1UL;
-       descriptor_status = (descriptor_status << 1) | descriptor_status2;
+       descriptor_status =
+               ((read_lmmr(offset) >> rshft) & UV_ACT_STATUS_MASK) << 1;
        return descriptor_status;
 }
 
@@ -531,87 +565,11 @@ int normal_busy(struct bau_control *bcp)
  */
 int handle_uv2_busy(struct bau_control *bcp)
 {
-       int busy_one = bcp->using_desc;
-       int normal = bcp->uvhub_cpu;
-       int selected = -1;
-       int i;
-       unsigned long descriptor_status;
-       unsigned long status;
-       int mmr_offset;
-       struct bau_desc *bau_desc_old;
-       struct bau_desc *bau_desc_new;
-       struct bau_control *hmaster = bcp->uvhub_master;
        struct ptc_stats *stat = bcp->statp;
-       cycles_t ttm;
 
        stat->s_uv2_wars++;
-       spin_lock(&hmaster->uvhub_lock);
-       /* try for the original first */
-       if (busy_one != normal) {
-               if (!normal_busy(bcp))
-                       selected = normal;
-       }
-       if (selected < 0) {
-               /* can't use the normal, select an alternate */
-               mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
-               descriptor_status = read_lmmr(mmr_offset);
-
-               /* scan available descriptors 32-63 */
-               for (i = 0; i < UV_CPUS_PER_AS; i++) {
-                       if ((hmaster->inuse_map & (1 << i)) == 0) {
-                               status = ((descriptor_status >>
-                                               (i * UV_ACT_STATUS_SIZE)) &
-                                               UV_ACT_STATUS_MASK) << 1;
-                               if (status != UV2H_DESC_BUSY) {
-                                       selected = i + UV_CPUS_PER_AS;
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       if (busy_one != normal)
-               /* mark the busy alternate as not in-use */
-               hmaster->inuse_map &= ~(1 << (busy_one - UV_CPUS_PER_AS));
-
-       if (selected >= 0) {
-               /* switch to the selected descriptor */
-               if (selected != normal) {
-                       /* set the selected alternate as in-use */
-                       hmaster->inuse_map |=
-                                       (1 << (selected - UV_CPUS_PER_AS));
-                       if (selected > stat->s_uv2_wars_hw)
-                               stat->s_uv2_wars_hw = selected;
-               }
-               bau_desc_old = bcp->descriptor_base;
-               bau_desc_old += (ITEMS_PER_DESC * busy_one);
-               bcp->using_desc = selected;
-               bau_desc_new = bcp->descriptor_base;
-               bau_desc_new += (ITEMS_PER_DESC * selected);
-               *bau_desc_new = *bau_desc_old;
-       } else {
-               /*
-                * All are busy. Wait for the normal one for this cpu to
-                * free up.
-                */
-               stat->s_uv2_war_waits++;
-               spin_unlock(&hmaster->uvhub_lock);
-               ttm = get_cycles();
-               do {
-                       cpu_relax();
-               } while (normal_busy(bcp));
-               spin_lock(&hmaster->uvhub_lock);
-               /* switch to the original descriptor */
-               bcp->using_desc = normal;
-               bau_desc_old = bcp->descriptor_base;
-               bau_desc_old += (ITEMS_PER_DESC * bcp->using_desc);
-               bcp->using_desc = (ITEMS_PER_DESC * normal);
-               bau_desc_new = bcp->descriptor_base;
-               bau_desc_new += (ITEMS_PER_DESC * normal);
-               *bau_desc_new = *bau_desc_old; /* copy the entire descriptor */
-       }
-       spin_unlock(&hmaster->uvhub_lock);
-       return FLUSH_RETRY_BUSYBUG;
+       bcp->busy = 1;
+       return FLUSH_GIVEUP;
 }
 
 static int uv2_wait_completion(struct bau_desc *bau_desc,
@@ -620,7 +578,7 @@ static int uv2_wait_completion(struct bau_desc *bau_desc,
 {
        unsigned long descriptor_stat;
        cycles_t ttm;
-       int desc = bcp->using_desc;
+       int desc = bcp->uvhub_cpu;
        long busy_reps = 0;
        struct ptc_stats *stat = bcp->statp;
 
@@ -628,24 +586,38 @@ static int uv2_wait_completion(struct bau_desc *bau_desc,
 
        /* spin on the status MMR, waiting for it to go idle */
        while (descriptor_stat != UV2H_DESC_IDLE) {
-               /*
-                * Our software ack messages may be blocked because
-                * there are no swack resources available.  As long
-                * as none of them has timed out hardware will NACK
-                * our message and its state will stay IDLE.
-                */
-               if ((descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT) ||
-                   (descriptor_stat == UV2H_DESC_DEST_PUT_ERR)) {
+               if ((descriptor_stat == UV2H_DESC_SOURCE_TIMEOUT)) {
+                       /*
+                        * A h/w bug on the destination side may
+                        * have prevented the message being marked
+                        * pending, thus it doesn't get replied to
+                        * and gets continually nacked until it times
+                        * out with a SOURCE_TIMEOUT.
+                        */
                        stat->s_stimeout++;
                        return FLUSH_GIVEUP;
-               } else if (descriptor_stat == UV2H_DESC_DEST_STRONG_NACK) {
-                       stat->s_strongnacks++;
-                       bcp->conseccompletes = 0;
-                       return FLUSH_GIVEUP;
                } else if (descriptor_stat == UV2H_DESC_DEST_TIMEOUT) {
+                       ttm = get_cycles();
+
+                       /*
+                        * Our retries may be blocked by all destination
+                        * swack resources being consumed, and a timeout
+                        * pending.  In that case hardware returns the
+                        * ERROR that looks like a destination timeout.
+                        * Without using the extended status we have to
+                        * deduce from the short time that this was a
+                        * strong nack.
+                        */
+                       if (cycles_2_us(ttm - bcp->send_message) < timeout_us) {
+                               bcp->conseccompletes = 0;
+                               stat->s_plugged++;
+                               /* FLUSH_RETRY_PLUGGED causes hang on boot */
+                               return FLUSH_GIVEUP;
+                       }
                        stat->s_dtimeout++;
                        bcp->conseccompletes = 0;
-                       return FLUSH_RETRY_TIMEOUT;
+                       /* FLUSH_RETRY_TIMEOUT causes hang on boot */
+                       return FLUSH_GIVEUP;
                } else {
                        busy_reps++;
                        if (busy_reps > 1000000) {
@@ -653,9 +625,8 @@ static int uv2_wait_completion(struct bau_desc *bau_desc,
                                busy_reps = 0;
                                ttm = get_cycles();
                                if ((ttm - bcp->send_message) >
-                                       (bcp->clocks_per_100_usec)) {
+                                               bcp->timeout_interval)
                                        return handle_uv2_busy(bcp);
-                               }
                        }
                        /*
                         * descriptor_stat is still BUSY
@@ -679,7 +650,7 @@ static int wait_completion(struct bau_desc *bau_desc,
 {
        int right_shift;
        unsigned long mmr_offset;
-       int desc = bcp->using_desc;
+       int desc = bcp->uvhub_cpu;
 
        if (desc < UV_CPUS_PER_AS) {
                mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
@@ -758,33 +729,31 @@ static void destination_timeout(struct bau_desc *bau_desc,
 }
 
 /*
- * Completions are taking a very long time due to a congested numalink
- * network.
+ * Stop all cpus on a uvhub from using the BAU for a period of time.
+ * This is reversed by check_enable.
  */
-static void disable_for_congestion(struct bau_control *bcp,
-                                       struct ptc_stats *stat)
+static void disable_for_period(struct bau_control *bcp, struct ptc_stats *stat)
 {
-       /* let only one cpu do this disabling */
-       spin_lock(&disable_lock);
-
-       if (!baudisabled && bcp->period_requests &&
-           ((bcp->period_time / bcp->period_requests) > congested_cycles)) {
-               int tcpu;
-               struct bau_control *tbcp;
-               /* it becomes this cpu's job to turn on the use of the
-                  BAU again */
-               baudisabled = 1;
-               bcp->set_bau_off = 1;
-               bcp->set_bau_on_time = get_cycles();
-               bcp->set_bau_on_time += sec_2_cycles(bcp->cong_period);
+       int tcpu;
+       struct bau_control *tbcp;
+       struct bau_control *hmaster;
+       cycles_t tm1;
+
+       hmaster = bcp->uvhub_master;
+       spin_lock(&hmaster->disable_lock);
+       if (!bcp->baudisabled) {
                stat->s_bau_disabled++;
+               tm1 = get_cycles();
                for_each_present_cpu(tcpu) {
                        tbcp = &per_cpu(bau_control, tcpu);
-                       tbcp->baudisabled = 1;
+                       if (tbcp->uvhub_master == hmaster) {
+                               tbcp->baudisabled = 1;
+                               tbcp->set_bau_on_time =
+                                       tm1 + bcp->disabled_period;
+                       }
                }
        }
-
-       spin_unlock(&disable_lock);
+       spin_unlock(&hmaster->disable_lock);
 }
 
 static void count_max_concurr(int stat, struct bau_control *bcp,
@@ -815,16 +784,30 @@ static void record_send_stats(cycles_t time1, cycles_t time2,
                        bcp->period_requests++;
                        bcp->period_time += elapsed;
                        if ((elapsed > congested_cycles) &&
-                           (bcp->period_requests > bcp->cong_reps))
-                               disable_for_congestion(bcp, stat);
+                           (bcp->period_requests > bcp->cong_reps) &&
+                           ((bcp->period_time / bcp->period_requests) >
+                                                       congested_cycles)) {
+                               stat->s_congested++;
+                               disable_for_period(bcp, stat);
+                       }
                }
        } else
                stat->s_requestor--;
 
        if (completion_status == FLUSH_COMPLETE && try > 1)
                stat->s_retriesok++;
-       else if (completion_status == FLUSH_GIVEUP)
+       else if (completion_status == FLUSH_GIVEUP) {
                stat->s_giveup++;
+               if (get_cycles() > bcp->period_end)
+                       bcp->period_giveups = 0;
+               bcp->period_giveups++;
+               if (bcp->period_giveups == 1)
+                       bcp->period_end = get_cycles() + bcp->disabled_period;
+               if (bcp->period_giveups > bcp->giveup_limit) {
+                       disable_for_period(bcp, stat);
+                       stat->s_giveuplimit++;
+               }
+       }
 }
 
 /*
@@ -868,7 +851,8 @@ static void handle_cmplt(int completion_status, struct bau_desc *bau_desc,
  * Returns 1 if it gives up entirely and the original cpu mask is to be
  * returned to the kernel.
  */
-int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
+int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp,
+       struct bau_desc *bau_desc)
 {
        int seq_number = 0;
        int completion_stat = 0;
@@ -881,24 +865,23 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
        struct bau_control *hmaster = bcp->uvhub_master;
        struct uv1_bau_msg_header *uv1_hdr = NULL;
        struct uv2_bau_msg_header *uv2_hdr = NULL;
-       struct bau_desc *bau_desc;
 
-       if (bcp->uvhub_version == 1)
+       if (bcp->uvhub_version == 1) {
+               uv1 = 1;
                uv1_throttle(hmaster, stat);
+       }
 
        while (hmaster->uvhub_quiesce)
                cpu_relax();
 
        time1 = get_cycles();
+       if (uv1)
+               uv1_hdr = &bau_desc->header.uv1_hdr;
+       else
+               uv2_hdr = &bau_desc->header.uv2_hdr;
+
        do {
-               bau_desc = bcp->descriptor_base;
-               bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
-               if (bcp->uvhub_version == 1) {
-                       uv1 = 1;
-                       uv1_hdr = &bau_desc->header.uv1_hdr;
-               } else
-                       uv2_hdr = &bau_desc->header.uv2_hdr;
-               if ((try == 0) || (completion_stat == FLUSH_RETRY_BUSYBUG)) {
+               if (try == 0) {
                        if (uv1)
                                uv1_hdr->msg_type = MSG_REGULAR;
                        else
@@ -916,25 +899,24 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
                        uv1_hdr->sequence = seq_number;
                else
                        uv2_hdr->sequence = seq_number;
-               index = (1UL << AS_PUSH_SHIFT) | bcp->using_desc;
+               index = (1UL << AS_PUSH_SHIFT) | bcp->uvhub_cpu;
                bcp->send_message = get_cycles();
 
                write_mmr_activation(index);
 
                try++;
                completion_stat = wait_completion(bau_desc, bcp, try);
-               /* UV2: wait_completion() may change the bcp->using_desc */
 
                handle_cmplt(completion_stat, bau_desc, bcp, hmaster, stat);
 
                if (bcp->ipi_attempts >= bcp->ipi_reset_limit) {
                        bcp->ipi_attempts = 0;
+                       stat->s_overipilimit++;
                        completion_stat = FLUSH_GIVEUP;
                        break;
                }
                cpu_relax();
        } while ((completion_stat == FLUSH_RETRY_PLUGGED) ||
-                (completion_stat == FLUSH_RETRY_BUSYBUG) ||
                 (completion_stat == FLUSH_RETRY_TIMEOUT));
 
        time2 = get_cycles();
@@ -955,28 +937,33 @@ int uv_flush_send_and_wait(struct cpumask *flush_mask, struct bau_control *bcp)
 }
 
 /*
- * The BAU is disabled. When the disabled time period has expired, the cpu
- * that disabled it must re-enable it.
- * Return 0 if it is re-enabled for all cpus.
+ * The BAU is disabled for this uvhub. When the disabled time period has
+ * expired re-enable it.
+ * Return 0 if it is re-enabled for all cpus on this uvhub.
  */
 static int check_enable(struct bau_control *bcp, struct ptc_stats *stat)
 {
        int tcpu;
        struct bau_control *tbcp;
+       struct bau_control *hmaster;
 
-       if (bcp->set_bau_off) {
-               if (get_cycles() >= bcp->set_bau_on_time) {
-                       stat->s_bau_reenabled++;
-                       baudisabled = 0;
-                       for_each_present_cpu(tcpu) {
-                               tbcp = &per_cpu(bau_control, tcpu);
+       hmaster = bcp->uvhub_master;
+       spin_lock(&hmaster->disable_lock);
+       if (bcp->baudisabled && (get_cycles() >= bcp->set_bau_on_time)) {
+               stat->s_bau_reenabled++;
+               for_each_present_cpu(tcpu) {
+                       tbcp = &per_cpu(bau_control, tcpu);
+                       if (tbcp->uvhub_master == hmaster) {
                                tbcp->baudisabled = 0;
                                tbcp->period_requests = 0;
                                tbcp->period_time = 0;
+                               tbcp->period_giveups = 0;
                        }
-                       return 0;
                }
+               spin_unlock(&hmaster->disable_lock);
+               return 0;
        }
+       spin_unlock(&hmaster->disable_lock);
        return -1;
 }
 
@@ -1078,18 +1065,32 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
        struct cpumask *flush_mask;
        struct ptc_stats *stat;
        struct bau_control *bcp;
-
-       /* kernel was booted 'nobau' */
-       if (nobau)
-               return cpumask;
+       unsigned long descriptor_status;
+       unsigned long status;
 
        bcp = &per_cpu(bau_control, cpu);
        stat = bcp->statp;
+       stat->s_enters++;
+
+       if (bcp->nobau)
+               return cpumask;
+
+       if (bcp->busy) {
+               descriptor_status =
+                       read_lmmr(UVH_LB_BAU_SB_ACTIVATION_STATUS_0);
+               status = ((descriptor_status >> (bcp->uvhub_cpu *
+                       UV_ACT_STATUS_SIZE)) & UV_ACT_STATUS_MASK) << 1;
+               if (status == UV2H_DESC_BUSY)
+                       return cpumask;
+               bcp->busy = 0;
+       }
 
        /* bau was disabled due to slow response */
        if (bcp->baudisabled) {
-               if (check_enable(bcp, stat))
+               if (check_enable(bcp, stat)) {
+                       stat->s_ipifordisabled++;
                        return cpumask;
+               }
        }
 
        /*
@@ -1105,7 +1106,7 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
                stat->s_ntargself++;
 
        bau_desc = bcp->descriptor_base;
-       bau_desc += (ITEMS_PER_DESC * bcp->using_desc);
+       bau_desc += (ITEMS_PER_DESC * bcp->uvhub_cpu);
        bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
        if (set_distrib_bits(flush_mask, bcp, bau_desc, &locals, &remotes))
                return NULL;
@@ -1118,25 +1119,27 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
         * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
         * or 1 if it gave up and the original cpumask should be returned.
         */
-       if (!uv_flush_send_and_wait(flush_mask, bcp))
+       if (!uv_flush_send_and_wait(flush_mask, bcp, bau_desc))
                return NULL;
        else
                return cpumask;
 }
 
 /*
- * Search the message queue for any 'other' message with the same software
- * acknowledge resource bit vector.
+ * Search the message queue for any 'other' unprocessed message with the
+ * same software acknowledge resource bit vector as the 'msg' message.
  */
 struct bau_pq_entry *find_another_by_swack(struct bau_pq_entry *msg,
-                       struct bau_control *bcp, unsigned char swack_vec)
+                                          struct bau_control *bcp)
 {
        struct bau_pq_entry *msg_next = msg + 1;
+       unsigned char swack_vec = msg->swack_vec;
 
        if (msg_next > bcp->queue_last)
                msg_next = bcp->queue_first;
-       while ((msg_next->swack_vec != 0) && (msg_next != msg)) {
-               if (msg_next->swack_vec == swack_vec)
+       while (msg_next != msg) {
+               if ((msg_next->canceled == 0) && (msg_next->replied_to == 0) &&
+                               (msg_next->swack_vec == swack_vec))
                        return msg_next;
                msg_next++;
                if (msg_next > bcp->queue_last)
@@ -1165,32 +1168,30 @@ void process_uv2_message(struct msg_desc *mdp, struct bau_control *bcp)
                 * This message was assigned a swack resource, but no
                 * reserved acknowlegment is pending.
                 * The bug has prevented this message from setting the MMR.
-                * And no other message has used the same sw_ack resource.
-                * Do the requested shootdown but do not reply to the msg.
-                * (the 0 means make no acknowledge)
                 */
-               bau_process_message(mdp, bcp, 0);
-               return;
-       }
-
-       /*
-        * Some message has set the MMR 'pending' bit; it might have been
-        * another message.  Look for that message.
-        */
-       other_msg = find_another_by_swack(msg, bcp, msg->swack_vec);
-       if (other_msg) {
-               /* There is another.  Do not ack the current one. */
-               bau_process_message(mdp, bcp, 0);
                /*
-                * Let the natural processing of that message acknowledge
-                * it. Don't get the processing of sw_ack's out of order.
+                * Some message has set the MMR 'pending' bit; it might have
+                * been another message.  Look for that message.
                 */
-               return;
+               other_msg = find_another_by_swack(msg, bcp);
+               if (other_msg) {
+                       /*
+                        * There is another. Process this one but do not
+                        * ack it.
+                        */
+                       bau_process_message(mdp, bcp, 0);
+                       /*
+                        * Let the natural processing of that other message
+                        * acknowledge it. Don't get the processing of sw_ack's
+                        * out of order.
+                        */
+                       return;
+               }
        }
 
        /*
-        * There is no other message using this sw_ack, so it is safe to
-        * acknowledge it.
+        * Either the MMR shows this one pending a reply or there is no
+        * other message using this sw_ack, so it is safe to acknowledge it.
         */
        bau_process_message(mdp, bcp, 1);
 
@@ -1295,7 +1296,8 @@ static void __init enable_timeouts(void)
                 */
                mmr_image |= (1L << SOFTACK_MSHIFT);
                if (is_uv2_hub()) {
-                       mmr_image |= (1L << UV2_EXT_SHFT);
+                       /* hw bug workaround; do not use extended status */
+                       mmr_image &= ~(1L << UV2_EXT_SHFT);
                }
                write_mmr_misc_control(pnode, mmr_image);
        }
@@ -1338,29 +1340,34 @@ static inline unsigned long long usec_2_cycles(unsigned long microsec)
 static int ptc_seq_show(struct seq_file *file, void *data)
 {
        struct ptc_stats *stat;
+       struct bau_control *bcp;
        int cpu;
 
        cpu = *(loff_t *)data;
        if (!cpu) {
                seq_printf(file,
-                       "# cpu sent stime self locals remotes ncpus localhub ");
+                "# cpu bauoff sent stime self locals remotes ncpus localhub ");
                seq_printf(file,
                        "remotehub numuvhubs numuvhubs16 numuvhubs8 ");
                seq_printf(file,
-                   "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries rok ");
+                       "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries ");
+               seq_printf(file,
+                       "rok resetp resett giveup sto bz throt disable ");
                seq_printf(file,
-                       "resetp resett giveup sto bz throt swack recv rtime ");
+                       "enable wars warshw warwaits enters ipidis plugged ");
                seq_printf(file,
-                       "all one mult none retry canc nocan reset rcan ");
+                       "ipiover glim cong swack recv rtime all one mult ");
                seq_printf(file,
-                       "disable enable wars warshw warwaits\n");
+                       "none retry canc nocan reset rcan\n");
        }
        if (cpu < num_possible_cpus() && cpu_online(cpu)) {
-               stat = &per_cpu(ptcstats, cpu);
+               bcp = &per_cpu(bau_control, cpu);
+               stat = bcp->statp;
                /* source side statistics */
                seq_printf(file,
-                       "cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
-                          cpu, stat->s_requestor, cycles_2_us(stat->s_time),
+                       "cpu %d %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+                          cpu, bcp->nobau, stat->s_requestor,
+                          cycles_2_us(stat->s_time),
                           stat->s_ntargself, stat->s_ntarglocals,
                           stat->s_ntargremotes, stat->s_ntargcpu,
                           stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
@@ -1374,20 +1381,23 @@ static int ptc_seq_show(struct seq_file *file, void *data)
                           stat->s_resets_plug, stat->s_resets_timeout,
                           stat->s_giveup, stat->s_stimeout,
                           stat->s_busy, stat->s_throttles);
+               seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+                          stat->s_bau_disabled, stat->s_bau_reenabled,
+                          stat->s_uv2_wars, stat->s_uv2_wars_hw,
+                          stat->s_uv2_war_waits, stat->s_enters,
+                          stat->s_ipifordisabled, stat->s_plugged,
+                          stat->s_overipilimit, stat->s_giveuplimit,
+                          stat->s_congested);
 
                /* destination side statistics */
                seq_printf(file,
-                          "%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+                       "%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n",
                           read_gmmr_sw_ack(uv_cpu_to_pnode(cpu)),
                           stat->d_requestee, cycles_2_us(stat->d_time),
                           stat->d_alltlb, stat->d_onetlb, stat->d_multmsg,
                           stat->d_nomsg, stat->d_retries, stat->d_canceled,
                           stat->d_nocanceled, stat->d_resets,
                           stat->d_rcanceled);
-               seq_printf(file, "%ld %ld %ld %ld %ld\n",
-                       stat->s_bau_disabled, stat->s_bau_reenabled,
-                       stat->s_uv2_wars, stat->s_uv2_wars_hw,
-                       stat->s_uv2_war_waits);
        }
        return 0;
 }
@@ -1401,13 +1411,14 @@ static ssize_t tunables_read(struct file *file, char __user *userbuf,
        char *buf;
        int ret;
 
-       buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d\n",
-               "max_concur plugged_delay plugsb4reset",
-               "timeoutsb4reset ipi_reset_limit complete_threshold",
-               "congested_response_us congested_reps congested_period",
+       buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d %d\n",
+               "max_concur plugged_delay plugsb4reset timeoutsb4reset",
+               "ipi_reset_limit complete_threshold congested_response_us",
+               "congested_reps disabled_period giveup_limit",
                max_concurr, plugged_delay, plugsb4reset,
                timeoutsb4reset, ipi_reset_limit, complete_threshold,
-               congested_respns_us, congested_reps, congested_period);
+               congested_respns_us, congested_reps, disabled_period,
+               giveup_limit);
 
        if (!buf)
                return -ENOMEM;
@@ -1438,6 +1449,14 @@ static ssize_t ptc_proc_write(struct file *file, const char __user *user,
                return -EFAULT;
        optstr[count - 1] = '\0';
 
+       if (!strcmp(optstr, "on")) {
+               set_bau_on();
+               return count;
+       } else if (!strcmp(optstr, "off")) {
+               set_bau_off();
+               return count;
+       }
+
        if (strict_strtol(optstr, 10, &input_arg) < 0) {
                printk(KERN_DEBUG "%s is invalid\n", optstr);
                return -EINVAL;
@@ -1570,7 +1589,8 @@ static ssize_t tunables_write(struct file *file, const char __user *user,
                bcp->complete_threshold =       complete_threshold;
                bcp->cong_response_us =         congested_respns_us;
                bcp->cong_reps =                congested_reps;
-               bcp->cong_period =              congested_period;
+               bcp->disabled_period =          sec_2_cycles(disabled_period);
+               bcp->giveup_limit =             giveup_limit;
        }
        return count;
 }
@@ -1699,6 +1719,10 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode)
                         *   fairness chaining multilevel count replied_to
                         */
                } else {
+                       /*
+                        * BIOS uses legacy mode, but UV2 hardware always
+                        * uses native mode for selective broadcasts.
+                        */
                        uv2_hdr = &bd2->header.uv2_hdr;
                        uv2_hdr->swack_flag =   1;
                        uv2_hdr->base_dest_nasid =
@@ -1811,8 +1835,8 @@ static int calculate_destination_timeout(void)
                index = (mmr_image >> BAU_URGENCY_7_SHIFT) & BAU_URGENCY_7_MASK;
                mmr_image = uv_read_local_mmr(UVH_TRANSACTION_TIMEOUT);
                mult2 = (mmr_image >> BAU_TRANS_SHIFT) & BAU_TRANS_MASK;
-               base = timeout_base_ns[index];
-               ts_ns = base * mult1 * mult2;
+               ts_ns = timeout_base_ns[index];
+               ts_ns *= (mult1 * mult2);
                ret = ts_ns / 1000;
        } else {
                /* 4 bits  0/1 for 10/80us base, 3 bits of multiplier */
@@ -1836,6 +1860,8 @@ static void __init init_per_cpu_tunables(void)
        for_each_present_cpu(cpu) {
                bcp = &per_cpu(bau_control, cpu);
                bcp->baudisabled                = 0;
+               if (nobau)
+                       bcp->nobau              = 1;
                bcp->statp                      = &per_cpu(ptcstats, cpu);
                /* time interval to catch a hardware stay-busy bug */
                bcp->timeout_interval           = usec_2_cycles(2*timeout_us);
@@ -1848,10 +1874,11 @@ static void __init init_per_cpu_tunables(void)
                bcp->complete_threshold         = complete_threshold;
                bcp->cong_response_us           = congested_respns_us;
                bcp->cong_reps                  = congested_reps;
-               bcp->cong_period                = congested_period;
-               bcp->clocks_per_100_usec =      usec_2_cycles(100);
+               bcp->disabled_period =          sec_2_cycles(disabled_period);
+               bcp->giveup_limit =             giveup_limit;
                spin_lock_init(&bcp->queue_lock);
                spin_lock_init(&bcp->uvhub_lock);
+               spin_lock_init(&bcp->disable_lock);
        }
 }
 
@@ -1972,7 +1999,6 @@ static int scan_sock(struct socket_desc *sdp, struct uvhub_desc *bdp,
                }
                bcp->uvhub_master = *hmasterp;
                bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->blade_processor_id;
-               bcp->using_desc = bcp->uvhub_cpu;
                if (bcp->uvhub_cpu >= MAX_CPUS_PER_UVHUB) {
                        printk(KERN_EMERG "%d cpus per uvhub invalid\n",
                                bcp->uvhub_cpu);
@@ -2069,16 +2095,12 @@ static int __init uv_bau_init(void)
        if (!is_uv_system())
                return 0;
 
-       if (nobau)
-               return 0;
-
        for_each_possible_cpu(cur_cpu) {
                mask = &per_cpu(uv_flush_tlb_mask, cur_cpu);
                zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
        }
 
        nuvhubs = uv_num_possible_blades();
-       spin_lock_init(&disable_lock);
        congested_cycles = usec_2_cycles(congested_respns_us);
 
        uv_base_pnode = 0x7fffffff;
@@ -2091,7 +2113,8 @@ static int __init uv_bau_init(void)
        enable_timeouts();
 
        if (init_per_cpu(nuvhubs, uv_base_pnode)) {
-               nobau = 1;
+               set_bau_off();
+               nobau_perm = 1;
                return 0;
        }
 
index f25c2765a5c9b48bbac24551dc2e82fc9e2d2ce2..acf7752da952f52cc43b56f5133f4d8fe97e56e4 100644 (file)
@@ -135,6 +135,7 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
        unsigned long mmr_value;
        struct uv_IO_APIC_route_entry *entry;
        int mmr_pnode, err;
+       unsigned int dest;
 
        BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
                        sizeof(unsigned long));
@@ -143,6 +144,10 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
        if (err != 0)
                return err;
 
+       err = apic->cpu_mask_to_apicid_and(eligible_cpu, eligible_cpu, &dest);
+       if (err != 0)
+               return err;
+
        if (limit == UV_AFFINITY_CPU)
                irq_set_status_flags(irq, IRQ_NO_BALANCING);
        else
@@ -159,7 +164,7 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
        entry->polarity         = 0;
        entry->trigger          = 0;
        entry->mask             = 0;
-       entry->dest             = apic->cpu_mask_to_apicid(eligible_cpu);
+       entry->dest             = dest;
 
        mmr_pnode = uv_blade_to_pnode(mmr_blade);
        uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
@@ -222,7 +227,7 @@ uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
        if (cfg->move_in_progress)
                send_cleanup_vector(cfg);
 
-       return 0;
+       return IRQ_SET_MASK_OK_NOCOPY;
 }
 
 /*
index 5b84a2d308885d9ce8c7e3f861fe269b721f1982..b2d534cab25fc1500c456efbde000779d794e229 100644 (file)
@@ -22,7 +22,7 @@ wakeup-objs   += video-bios.o
 realmode-y                     += header.o
 realmode-y                     += trampoline_$(BITS).o
 realmode-y                     += stack.o
-realmode-$(CONFIG_X86_32)      += reboot_32.o
+realmode-y                     += reboot.o
 realmode-$(CONFIG_ACPI_SLEEP)  += $(wakeup-objs)
 
 targets        += $(realmode-y)
index fadf48378adac71fdd9d4ef76f74b876e0572aa7..a28221d94e69eb60fc18aab9c5997ed52a7a763f 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/linkage.h>
 #include <asm/page_types.h>
+#include <asm/segment.h>
 
 #include "realmode.h"
        
@@ -28,8 +29,9 @@ GLOBAL(real_mode_header)
        .long   pa_wakeup_header
 #endif
        /* APM/BIOS reboot */
-#ifdef CONFIG_X86_32
        .long   pa_machine_real_restart_asm
+#ifdef CONFIG_X86_64
+       .long   __KERNEL32_CS
 #endif
 END(real_mode_header)
 
similarity index 85%
rename from arch/x86/realmode/rm/reboot_32.S
rename to arch/x86/realmode/rm/reboot.S
index 114044876b3df091c388f0a8d362115a646ee8b2..f932ea61d1c844fd39fc4024570c0c334ee8a0b6 100644 (file)
@@ -2,6 +2,8 @@
 #include <linux/init.h>
 #include <asm/segment.h>
 #include <asm/page_types.h>
+#include <asm/processor-flags.h>
+#include <asm/msr-index.h>
 #include "realmode.h"
 
 /*
  * doesn't work with at least one type of 486 motherboard.  It is easy
  * to stop this code working; hence the copious comments.
  *
- * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
+ * This code is called with the restart type (0 = BIOS, 1 = APM) in
+ * the primary argument register (%eax for 32 bit, %edi for 64 bit).
  */
        .section ".text32", "ax"
        .code32
-
-       .balign 16
 ENTRY(machine_real_restart_asm)
+
+#ifdef CONFIG_X86_64
+       /* Switch to trampoline GDT as it is guaranteed < 4 GiB */
+       movl    $__KERNEL_DS, %eax
+       movl    %eax, %ds
+       lgdtl   pa_tr_gdt
+
+       /* Disable paging to drop us out of long mode */
+       movl    %cr0, %eax
+       andl    $~X86_CR0_PG, %eax
+       movl    %eax, %cr0
+       ljmpl   $__KERNEL32_CS, $pa_machine_real_restart_paging_off
+
+GLOBAL(machine_real_restart_paging_off)
+       xorl    %eax, %eax
+       xorl    %edx, %edx
+       movl    $MSR_EFER, %ecx
+       wrmsr
+
+       movl    %edi, %eax
+       
+#endif /* CONFIG_X86_64 */
+       
        /* Set up the IDT for real mode. */
        lidtl   pa_machine_real_restart_idt
 
index 66e6d93598262a2877666f1d1163125207f9c89a..0faad646f5fda8eb40c64a95e685c2c919daadf6 100644 (file)
@@ -205,9 +205,9 @@ void syscall32_cpu_init(void)
 {
        /* Load these always in case some future AMD CPU supports
           SYSENTER from compat mode too. */
-       checking_wrmsrl(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
-       checking_wrmsrl(MSR_IA32_SYSENTER_ESP, 0ULL);
-       checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
+       wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
+       wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL);
+       wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target);
 
        wrmsrl(MSR_CSTAR, ia32_cstar_target);
 }
index ff962d4b821e5162415fa06ddf75e8c57d498b51..ed7d54985d0cb558b6e4177d2891a9609fa3e1e6 100644 (file)
@@ -1124,9 +1124,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .wbinvd = native_wbinvd,
 
        .read_msr = native_read_msr_safe,
-       .rdmsr_regs = native_rdmsr_safe_regs,
        .write_msr = xen_write_msr_safe,
-       .wrmsr_regs = native_wrmsr_safe_regs,
 
        .read_tsc = native_read_tsc,
        .read_pmc = native_read_pmc,
index afb250d22a6b2e29cf96f54e48bc6f619dab2ca7..f58dca7a6e52cef85503753f4b500d4d8f7ec369 100644 (file)
@@ -80,9 +80,7 @@ static void __cpuinit cpu_bringup(void)
 
        notify_cpu_starting(cpu);
 
-       ipi_call_lock();
        set_cpu_online(cpu, true);
-       ipi_call_unlock();
 
        this_cpu_write(cpu_state, CPU_ONLINE);
 
index 9b306e550e3f06ddfa342c041c7793543702c4b3..2c8d6a3d250afd2d18fa8b41b03dc26b0ad97ca2 100644 (file)
@@ -277,7 +277,7 @@ void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
 
        /* Don't leak any random bits. */
 
-       memset(elfregs, 0, sizeof (elfregs));
+       memset(elfregs, 0, sizeof(*elfregs));
 
        /* Note:  PS.EXCM is not set while user task is running; its
         * being set in regs->ps is for exception handling convenience.
index 02cf6335e9bdc5bb940ec89fcdbfe63746f9b5df..e7dee617358e810aec57ff25162ff95604fabb3c 100644 (file)
@@ -125,12 +125,8 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q)
 
                blkg->pd[i] = pd;
                pd->blkg = blkg;
-       }
-
-       /* invoke per-policy init */
-       for (i = 0; i < BLKCG_MAX_POLS; i++) {
-               struct blkcg_policy *pol = blkcg_policy[i];
 
+               /* invoke per-policy init */
                if (blkcg_policy_enabled(blkg->q, pol))
                        pol->pd_init_fn(blkg);
        }
@@ -245,10 +241,9 @@ EXPORT_SYMBOL_GPL(blkg_lookup_create);
 
 static void blkg_destroy(struct blkcg_gq *blkg)
 {
-       struct request_queue *q = blkg->q;
        struct blkcg *blkcg = blkg->blkcg;
 
-       lockdep_assert_held(q->queue_lock);
+       lockdep_assert_held(blkg->q->queue_lock);
        lockdep_assert_held(&blkcg->lock);
 
        /* Something wrong if we are trying to remove same group twice */
index 3c923a7aeb56f1658142b091868c3c29ebffd3c5..93eb3e4f88ce78affc79c5ca6d8b7c7b0759be5a 100644 (file)
@@ -361,9 +361,10 @@ EXPORT_SYMBOL(blk_put_queue);
  */
 void blk_drain_queue(struct request_queue *q, bool drain_all)
 {
+       int i;
+
        while (true) {
                bool drain = false;
-               int i;
 
                spin_lock_irq(q->queue_lock);
 
@@ -408,6 +409,18 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
                        break;
                msleep(10);
        }
+
+       /*
+        * With queue marked dead, any woken up waiter will fail the
+        * allocation path, so the wakeup chaining is lost and we're
+        * left with hung waiters. We need to wake up those waiters.
+        */
+       if (q->request_fn) {
+               spin_lock_irq(q->queue_lock);
+               for (i = 0; i < ARRAY_SIZE(q->rq.wait); i++)
+                       wake_up_all(&q->rq.wait[i]);
+               spin_unlock_irq(q->queue_lock);
+       }
 }
 
 /**
@@ -467,7 +480,6 @@ void blk_cleanup_queue(struct request_queue *q)
        /* mark @q DEAD, no new request or merges will be allowed afterwards */
        mutex_lock(&q->sysfs_lock);
        queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
-
        spin_lock_irq(lock);
 
        /*
@@ -485,10 +497,6 @@ void blk_cleanup_queue(struct request_queue *q)
        queue_flag_set(QUEUE_FLAG_NOMERGES, q);
        queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
        queue_flag_set(QUEUE_FLAG_DEAD, q);
-
-       if (q->queue_lock != &q->__queue_lock)
-               q->queue_lock = &q->__queue_lock;
-
        spin_unlock_irq(lock);
        mutex_unlock(&q->sysfs_lock);
 
@@ -499,6 +507,11 @@ void blk_cleanup_queue(struct request_queue *q)
        del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
        blk_sync_queue(q);
 
+       spin_lock_irq(lock);
+       if (q->queue_lock != &q->__queue_lock)
+               q->queue_lock = &q->__queue_lock;
+       spin_unlock_irq(lock);
+
        /* @q is and will stay empty, shutdown and put */
        blk_put_queue(q);
 }
index 780354888958cd7ea03aef2c1654b325bc9fb24e..6e4744cbfb56b4ca0d99062a0d9b0437c894016d 100644 (file)
@@ -197,44 +197,3 @@ void blk_add_timer(struct request *req)
                mod_timer(&q->timeout, expiry);
 }
 
-/**
- * blk_abort_queue -- Abort all request on given queue
- * @queue:     pointer to queue
- *
- */
-void blk_abort_queue(struct request_queue *q)
-{
-       unsigned long flags;
-       struct request *rq, *tmp;
-       LIST_HEAD(list);
-
-       /*
-        * Not a request based block device, nothing to abort
-        */
-       if (!q->request_fn)
-               return;
-
-       spin_lock_irqsave(q->queue_lock, flags);
-
-       elv_abort_queue(q);
-
-       /*
-        * Splice entries to local list, to avoid deadlocking if entries
-        * get readded to the timeout list by error handling
-        */
-       list_splice_init(&q->timeout_list, &list);
-
-       list_for_each_entry_safe(rq, tmp, &list, timeout_list)
-               blk_abort_request(rq);
-
-       /*
-        * Occasionally, blk_abort_request() will return without
-        * deleting the element from the list. Make sure we add those back
-        * instead of leaving them on the local stack list.
-        */
-       list_splice(&list, &q->timeout_list);
-
-       spin_unlock_irqrestore(q->queue_lock, flags);
-
-}
-EXPORT_SYMBOL_GPL(blk_abort_queue);
index 673c977cc2bfa238e0fe0efa6dddac5193fbccd8..fb52df9744f5fe411908162fbb02257ca0bc097a 100644 (file)
@@ -17,8 +17,6 @@
 #include "blk.h"
 #include "blk-cgroup.h"
 
-static struct blkcg_policy blkcg_policy_cfq __maybe_unused;
-
 /*
  * tunables
  */
@@ -418,11 +416,6 @@ static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd)
        return pd ? container_of(pd, struct cfq_group, pd) : NULL;
 }
 
-static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
-{
-       return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
-}
-
 static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg)
 {
        return pd_to_blkg(&cfqg->pd);
@@ -572,6 +565,13 @@ static inline void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) { }
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
 
+static struct blkcg_policy blkcg_policy_cfq;
+
+static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg)
+{
+       return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq));
+}
+
 static inline void cfqg_get(struct cfq_group *cfqg)
 {
        return blkg_get(cfqg_to_blkg(cfqg));
@@ -3951,10 +3951,11 @@ static void cfq_exit_queue(struct elevator_queue *e)
 
        cfq_shutdown_timer_wq(cfqd);
 
-#ifndef CONFIG_CFQ_GROUP_IOSCHED
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       blkcg_deactivate_policy(q, &blkcg_policy_cfq);
+#else
        kfree(cfqd->root_group);
 #endif
-       blkcg_deactivate_policy(q, &blkcg_policy_cfq);
        kfree(cfqd);
 }
 
@@ -4194,14 +4195,15 @@ static int __init cfq_init(void)
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
        if (!cfq_group_idle)
                cfq_group_idle = 1;
-#else
-               cfq_group_idle = 0;
-#endif
 
        ret = blkcg_policy_register(&blkcg_policy_cfq);
        if (ret)
                return ret;
+#else
+       cfq_group_idle = 0;
+#endif
 
+       ret = -ENOMEM;
        cfq_pool = KMEM_CACHE(cfq_queue, 0);
        if (!cfq_pool)
                goto err_pol_unreg;
@@ -4215,13 +4217,17 @@ static int __init cfq_init(void)
 err_free_pool:
        kmem_cache_destroy(cfq_pool);
 err_pol_unreg:
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
        blkcg_policy_unregister(&blkcg_policy_cfq);
+#endif
        return ret;
 }
 
 static void __exit cfq_exit(void)
 {
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
        blkcg_policy_unregister(&blkcg_policy_cfq);
+#endif
        elv_unregister(&iosched_cfq);
        kmem_cache_destroy(cfq_pool);
 }
index 260fa80ef5750f80f4ebc1415d06abc992e18b8a..9a87daa6f4fbd10202ea9d47ae1a549c806a6fb4 100644 (file)
@@ -721,11 +721,14 @@ int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd)
                break;
        }
 
+       if (capable(CAP_SYS_RAWIO))
+               return 0;
+
        /* In particular, rule out all resets and host-specific ioctls.  */
        printk_ratelimited(KERN_WARNING
                           "%s: sending ioctl %x to a partition!\n", current->comm, cmd);
 
-       return capable(CAP_SYS_RAWIO) ? 0 : -ENOIOCTLCMD;
+       return -ENOIOCTLCMD;
 }
 EXPORT_SYMBOL(scsi_verify_blk_ioctl);
 
index 6512b20aeccdce0184a6a5c524af85c6f7f6db91..ff9f6bd483013b44d1dd152ad17df1e3030a8a9d 100644 (file)
@@ -61,7 +61,6 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file);
 
 static int acpi_ac_add(struct acpi_device *device);
 static int acpi_ac_remove(struct acpi_device *device, int type);
-static int acpi_ac_resume(struct acpi_device *device);
 static void acpi_ac_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id ac_device_ids[] = {
@@ -70,6 +69,9 @@ static const struct acpi_device_id ac_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, ac_device_ids);
 
+static int acpi_ac_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
+
 static struct acpi_driver acpi_ac_driver = {
        .name = "ac",
        .class = ACPI_AC_CLASS,
@@ -78,9 +80,9 @@ static struct acpi_driver acpi_ac_driver = {
        .ops = {
                .add = acpi_ac_add,
                .remove = acpi_ac_remove,
-               .resume = acpi_ac_resume,
                .notify = acpi_ac_notify,
                },
+       .drv.pm = &acpi_ac_pm,
 };
 
 struct acpi_ac {
@@ -309,13 +311,18 @@ static int acpi_ac_add(struct acpi_device *device)
        return result;
 }
 
-static int acpi_ac_resume(struct acpi_device *device)
+static int acpi_ac_resume(struct device *dev)
 {
        struct acpi_ac *ac;
        unsigned old_state;
-       if (!device || !acpi_driver_data(device))
+
+       if (!dev)
                return -EINVAL;
-       ac = acpi_driver_data(device);
+
+       ac = acpi_driver_data(to_acpi_device(dev));
+       if (!ac)
+               return -EINVAL;
+
        old_state = ac->state;
        if (acpi_ac_get_state(ac))
                return 0;
index 0ed85cac32314f956de3092f7087e3ab011b5ba7..615996a36bedcef10f63bc929b21b3861c9781c6 100644 (file)
@@ -95,18 +95,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
                return_ACPI_STATUS(status);
        }
 
-       if (sleep_state != ACPI_STATE_S5) {
-               /*
-                * Disable BM arbitration. This feature is contained within an
-                * optional register (PM2 Control), so ignore a BAD_ADDRESS
-                * exception.
-                */
-               status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
-               if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
-                       return_ACPI_STATUS(status);
-               }
-       }
-
        /*
         * 1) Disable/Clear all GPEs
         * 2) Enable all wakeup GPEs
@@ -364,16 +352,6 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags)
                                    [ACPI_EVENT_POWER_BUTTON].
                                    status_register_id, ACPI_CLEAR_STATUS);
 
-       /*
-        * Enable BM arbitration. This feature is contained within an
-        * optional register (PM2 Control), so ignore a BAD_ADDRESS
-        * exception.
-        */
-       status = acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
-       if (ACPI_FAILURE(status) && (status != AE_BAD_ADDRESS)) {
-               return_ACPI_STATUS(status);
-       }
-
        acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
        return_ACPI_STATUS(status);
 }
index 23ce096864186a1cfd6ced9e57fd17d208646004..fe6626035495bb398fbf2d7fc7097d195a916d29 100644 (file)
@@ -638,7 +638,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
                        /* Create the new outer package and populate it */
 
                        status =
-                           acpi_ns_wrap_with_package(data, *elements,
+                           acpi_ns_wrap_with_package(data, return_object,
                                                      return_object_ptr);
                        if (ACPI_FAILURE(status)) {
                                return (status);
index 7dd3f9fb9f3f21b808e30b8aa78f65fce7b2275a..023f9c8534d0607c3d6532b43e696961800d9e6c 100644 (file)
@@ -1044,17 +1044,24 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
 }
 
 /* this is needed to learn about changes made in suspended state */
-static int acpi_battery_resume(struct acpi_device *device)
+static int acpi_battery_resume(struct device *dev)
 {
        struct acpi_battery *battery;
-       if (!device)
+
+       if (!dev)
                return -EINVAL;
-       battery = acpi_driver_data(device);
+
+       battery = acpi_driver_data(to_acpi_device(dev));
+       if (!battery)
+               return -EINVAL;
+
        battery->update_time = 0;
        acpi_battery_update(battery);
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
+
 static struct acpi_driver acpi_battery_driver = {
        .name = "battery",
        .class = ACPI_BATTERY_CLASS,
@@ -1062,10 +1069,10 @@ static struct acpi_driver acpi_battery_driver = {
        .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
        .ops = {
                .add = acpi_battery_add,
-               .resume = acpi_battery_resume,
                .remove = acpi_battery_remove,
                .notify = acpi_battery_notify,
                },
+       .drv.pm = &acpi_battery_pm,
 };
 
 static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
index d27d072472f9a638fac8da78d507438b0bb3bf5e..79d4c22f7a6d82c21e786b591f02f8bfe28b0f43 100644 (file)
@@ -76,19 +76,21 @@ MODULE_DEVICE_TABLE(acpi, button_device_ids);
 
 static int acpi_button_add(struct acpi_device *device);
 static int acpi_button_remove(struct acpi_device *device, int type);
-static int acpi_button_resume(struct acpi_device *device);
 static void acpi_button_notify(struct acpi_device *device, u32 event);
 
+static int acpi_button_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
+
 static struct acpi_driver acpi_button_driver = {
        .name = "button",
        .class = ACPI_BUTTON_CLASS,
        .ids = button_device_ids,
        .ops = {
                .add = acpi_button_add,
-               .resume = acpi_button_resume,
                .remove = acpi_button_remove,
                .notify = acpi_button_notify,
        },
+       .drv.pm = &acpi_button_pm,
 };
 
 struct acpi_button {
@@ -308,8 +310,9 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
        }
 }
 
-static int acpi_button_resume(struct acpi_device *device)
+static int acpi_button_resume(struct device *dev)
 {
+       struct acpi_device *device = to_acpi_device(dev);
        struct acpi_button *button = acpi_driver_data(device);
 
        if (button->type == ACPI_BUTTON_TYPE_LID)
index 0f0356ca1a9e99c24bd17f63e910538e63fc7a79..669d9ee80d1678b7665a3b4b8b2ad709743a44aa 100644 (file)
@@ -46,8 +46,6 @@ MODULE_LICENSE("GPL");
 
 static int acpi_fan_add(struct acpi_device *device);
 static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
-static int acpi_fan_resume(struct acpi_device *device);
 
 static const struct acpi_device_id fan_device_ids[] = {
        {"PNP0C0B", 0},
@@ -55,6 +53,10 @@ static const struct acpi_device_id fan_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, fan_device_ids);
 
+static int acpi_fan_suspend(struct device *dev);
+static int acpi_fan_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
+
 static struct acpi_driver acpi_fan_driver = {
        .name = "fan",
        .class = ACPI_FAN_CLASS,
@@ -62,9 +64,8 @@ static struct acpi_driver acpi_fan_driver = {
        .ops = {
                .add = acpi_fan_add,
                .remove = acpi_fan_remove,
-               .suspend = acpi_fan_suspend,
-               .resume = acpi_fan_resume,
                },
+       .drv.pm = &acpi_fan_pm,
 };
 
 /* thermal cooling device callbacks */
@@ -183,24 +184,24 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
+static int acpi_fan_suspend(struct device *dev)
 {
-       if (!device)
+       if (!dev)
                return -EINVAL;
 
-       acpi_bus_set_power(device->handle, ACPI_STATE_D0);
+       acpi_bus_set_power(to_acpi_device(dev)->handle, ACPI_STATE_D0);
 
        return AE_OK;
 }
 
-static int acpi_fan_resume(struct acpi_device *device)
+static int acpi_fan_resume(struct device *dev)
 {
        int result;
 
-       if (!device)
+       if (!dev)
                return -EINVAL;
 
-       result = acpi_bus_update_power(device->handle, NULL);
+       result = acpi_bus_update_power(to_acpi_device(dev)->handle, NULL);
        if (result)
                printk(KERN_ERR PREFIX "Error updating fan power state\n");
 
index dd6d6a3c6780d7e787c1c3427b808618d8c64fa4..894d45c6bc67793d84198416fe1940e2fe42dc19 100644 (file)
@@ -60,7 +60,6 @@ ACPI_MODULE_NAME("power");
 
 static int acpi_power_add(struct acpi_device *device);
 static int acpi_power_remove(struct acpi_device *device, int type);
-static int acpi_power_resume(struct acpi_device *device);
 
 static const struct acpi_device_id power_device_ids[] = {
        {ACPI_POWER_HID, 0},
@@ -68,6 +67,9 @@ static const struct acpi_device_id power_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, power_device_ids);
 
+static int acpi_power_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_power_pm, NULL, acpi_power_resume);
+
 static struct acpi_driver acpi_power_driver = {
        .name = "power",
        .class = ACPI_POWER_CLASS,
@@ -75,8 +77,8 @@ static struct acpi_driver acpi_power_driver = {
        .ops = {
                .add = acpi_power_add,
                .remove = acpi_power_remove,
-               .resume = acpi_power_resume,
                },
+       .drv.pm = &acpi_power_pm,
 };
 
 /*
@@ -771,14 +773,16 @@ static int acpi_power_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int acpi_power_resume(struct acpi_device *device)
+static int acpi_power_resume(struct device *dev)
 {
        int result = 0, state;
+       struct acpi_device *device;
        struct acpi_power_resource *resource;
 
-       if (!device)
+       if (!dev)
                return -EINVAL;
 
+       device = to_acpi_device(dev);
        resource = acpi_driver_data(device);
        if (!resource)
                return -EINVAL;
index c850de4c9a146883a7d91f16c8cd8ddc3b694940..eff722278ff539535bec85d5f5f6f4f2b04b79bf 100644 (file)
@@ -189,10 +189,12 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
                 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
                 * }
                 *
-                * Ignores apic_id and always return 0 for CPU0's handle.
+                * Ignores apic_id and always returns 0 for the processor
+                * handle with acpi id 0 if nr_cpu_ids is 1.
+                * This should be the case if SMP tables are not found.
                 * Return -1 for other CPU's handle.
                 */
-               if (acpi_id == 0)
+               if (nr_cpu_ids <= 1 && acpi_id == 0)
                        return acpi_id;
                else
                        return apic_id;
index 0734086537b89732ba805158389b904e94ae7ecf..7048b97853e0f547acb2347b76393193c4809e4e 100644 (file)
@@ -93,6 +93,9 @@ static const struct acpi_device_id processor_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, processor_device_ids);
 
+static SIMPLE_DEV_PM_OPS(acpi_processor_pm,
+                        acpi_processor_suspend, acpi_processor_resume);
+
 static struct acpi_driver acpi_processor_driver = {
        .name = "processor",
        .class = ACPI_PROCESSOR_CLASS,
@@ -100,10 +103,9 @@ static struct acpi_driver acpi_processor_driver = {
        .ops = {
                .add = acpi_processor_add,
                .remove = acpi_processor_remove,
-               .suspend = acpi_processor_suspend,
-               .resume = acpi_processor_resume,
                .notify = acpi_processor_notify,
                },
+       .drv.pm = &acpi_processor_pm,
 };
 
 #define INSTALL_NOTIFY_HANDLER         1
@@ -427,18 +429,11 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
                 * Initialize missing things
                 */
                if (pr->flags.need_hotplug_init) {
-                       struct cpuidle_driver *idle_driver =
-                               cpuidle_get_driver();
-
                        printk(KERN_INFO "Will online and init hotplugged "
                               "CPU: %d\n", pr->id);
                        WARN(acpi_processor_start(pr), "Failed to start CPU:"
                                " %d\n", pr->id);
                        pr->flags.need_hotplug_init = 0;
-                       if (idle_driver && !strcmp(idle_driver->name,
-                                                  "intel_idle")) {
-                               intel_idle_cpu_init(pr->id);
-                       }
                /* Normal CPU soft online event */
                } else {
                        acpi_processor_ppc_has_changed(pr, 0);
index 47a8caa89dbe58fc00bafa17bc75e2dba079eb8a..e589c1985248b6832b0756b861ca32f894468ad9 100644 (file)
@@ -221,10 +221,6 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
 
 #endif
 
-/*
- * Suspend / resume control
- */
-static int acpi_idle_suspend;
 static u32 saved_bm_rld;
 
 static void acpi_idle_bm_rld_save(void)
@@ -241,23 +237,15 @@ static void acpi_idle_bm_rld_restore(void)
                acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
 }
 
-int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
+int acpi_processor_suspend(struct device *dev)
 {
-       if (acpi_idle_suspend == 1)
-               return 0;
-
        acpi_idle_bm_rld_save();
-       acpi_idle_suspend = 1;
        return 0;
 }
 
-int acpi_processor_resume(struct acpi_device * device)
+int acpi_processor_resume(struct device *dev)
 {
-       if (acpi_idle_suspend == 0)
-               return 0;
-
        acpi_idle_bm_rld_restore();
-       acpi_idle_suspend = 0;
        return 0;
 }
 
@@ -595,7 +583,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
         */
        cx->valid = 1;
 
-       cx->latency_ticks = cx->latency;
        /*
         * On older chipsets, BM_RLD needs to be set
         * in order for Bus Master activity to wake the
@@ -628,7 +615,6 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
                        if (!cx->address)
                                break;
                        cx->valid = 1; 
-                       cx->latency_ticks = cx->latency; /* Normalize latency */
                        break;
 
                case ACPI_STATE_C3:
@@ -763,11 +749,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
 
        local_irq_disable();
 
-       if (acpi_idle_suspend) {
-               local_irq_enable();
-               cpu_relax();
-               return -EBUSY;
-       }
 
        lapic_timer_state_broadcast(pr, cx, 1);
        kt1 = ktime_get_real();
@@ -779,7 +760,6 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
        dev->last_residency = (int)idle_time;
 
        local_irq_enable();
-       cx->usage++;
        lapic_timer_state_broadcast(pr, cx, 0);
 
        return index;
@@ -838,11 +818,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
        local_irq_disable();
 
-       if (acpi_idle_suspend) {
-               local_irq_enable();
-               cpu_relax();
-               return -EBUSY;
-       }
 
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
@@ -887,10 +862,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        if (cx->entry_method != ACPI_CSTATE_FFH)
                current_thread_info()->status |= TS_POLLING;
 
-       cx->usage++;
-
        lapic_timer_state_broadcast(pr, cx, 0);
-       cx->time += idle_time;
        return index;
 }
 
@@ -928,8 +900,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                                                drv, drv->safe_state_index);
                } else {
                        local_irq_disable();
-                       if (!acpi_idle_suspend)
-                               acpi_safe_halt();
+                       acpi_safe_halt();
                        local_irq_enable();
                        return -EBUSY;
                }
@@ -937,11 +908,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 
        local_irq_disable();
 
-       if (acpi_idle_suspend) {
-               local_irq_enable();
-               cpu_relax();
-               return -EBUSY;
-       }
 
        if (cx->entry_method != ACPI_CSTATE_FFH) {
                current_thread_info()->status &= ~TS_POLLING;
@@ -1014,10 +980,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        if (cx->entry_method != ACPI_CSTATE_FFH)
                current_thread_info()->status |= TS_POLLING;
 
-       cx->usage++;
-
        lapic_timer_state_broadcast(pr, cx, 0);
-       cx->time += idle_time;
        return index;
 }
 
index 6e36d0c0057c1303464aca74ba0a2b1d9ad3bc25..c0b9aa5faf4cdfd8d354fa89e8204704714cccf1 100644 (file)
@@ -988,16 +988,18 @@ static void acpi_sbs_rmdirs(void)
 #endif
 }
 
-static int acpi_sbs_resume(struct acpi_device *device)
+static int acpi_sbs_resume(struct device *dev)
 {
        struct acpi_sbs *sbs;
-       if (!device)
+       if (!dev)
                return -EINVAL;
-       sbs = device->driver_data;
+       sbs = to_acpi_device(dev)->driver_data;
        acpi_sbs_callback(sbs);
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
+
 static struct acpi_driver acpi_sbs_driver = {
        .name = "sbs",
        .class = ACPI_SBS_CLASS,
@@ -1005,8 +1007,8 @@ static struct acpi_driver acpi_sbs_driver = {
        .ops = {
                .add = acpi_sbs_add,
                .remove = acpi_sbs_remove,
-               .resume = acpi_sbs_resume,
                },
+       .drv.pm = &acpi_sbs_pm,
 };
 
 static int __init acpi_sbs_init(void)
index c8a1f3b68110b86dd2c6b0ddddc91ee2085e93b1..fdda49336560acd2b0eb766430a811d6d842bf0c 100644 (file)
@@ -290,26 +290,6 @@ static void acpi_device_release(struct device *dev)
        kfree(acpi_dev);
 }
 
-static int acpi_device_suspend(struct device *dev, pm_message_t state)
-{
-       struct acpi_device *acpi_dev = to_acpi_device(dev);
-       struct acpi_driver *acpi_drv = acpi_dev->driver;
-
-       if (acpi_drv && acpi_drv->ops.suspend)
-               return acpi_drv->ops.suspend(acpi_dev, state);
-       return 0;
-}
-
-static int acpi_device_resume(struct device *dev)
-{
-       struct acpi_device *acpi_dev = to_acpi_device(dev);
-       struct acpi_driver *acpi_drv = acpi_dev->driver;
-
-       if (acpi_drv && acpi_drv->ops.resume)
-               return acpi_drv->ops.resume(acpi_dev);
-       return 0;
-}
-
 static int acpi_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
@@ -441,8 +421,6 @@ static int acpi_device_remove(struct device * dev)
 
 struct bus_type acpi_bus_type = {
        .name           = "acpi",
-       .suspend        = acpi_device_suspend,
-       .resume         = acpi_device_resume,
        .match          = acpi_bus_match,
        .probe          = acpi_device_probe,
        .remove         = acpi_device_remove,
index 7dbebea1ec31302bcb3eaac60d0aa3dd8fb9f7af..21dd4c268aefca37746498da131edee6a8c574f0 100644 (file)
@@ -98,7 +98,6 @@ MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
 
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_remove(struct acpi_device *device, int type);
-static int acpi_thermal_resume(struct acpi_device *device);
 static void acpi_thermal_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id  thermal_device_ids[] = {
@@ -107,6 +106,9 @@ static const struct acpi_device_id  thermal_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 
+static int acpi_thermal_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
+
 static struct acpi_driver acpi_thermal_driver = {
        .name = "thermal",
        .class = ACPI_THERMAL_CLASS,
@@ -114,9 +116,9 @@ static struct acpi_driver acpi_thermal_driver = {
        .ops = {
                .add = acpi_thermal_add,
                .remove = acpi_thermal_remove,
-               .resume = acpi_thermal_resume,
                .notify = acpi_thermal_notify,
                },
+       .drv.pm = &acpi_thermal_pm,
 };
 
 struct acpi_thermal_state {
@@ -1041,16 +1043,17 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int acpi_thermal_resume(struct acpi_device *device)
+static int acpi_thermal_resume(struct device *dev)
 {
-       struct acpi_thermal *tz = NULL;
+       struct acpi_thermal *tz;
        int i, j, power_state, result;
 
-
-       if (!device || !acpi_driver_data(device))
+       if (!dev)
                return -EINVAL;
 
-       tz = acpi_driver_data(device);
+       tz = acpi_driver_data(to_acpi_device(dev));
+       if (!tz)
+               return -EINVAL;
 
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
                if (!(&tz->trips.active[i]))
index aa0b1f16052875a9af91dcc46cbc755259a7baa3..0b6f0b28a4872b2aa32fe6f1e656ff1ae4ca213d 100644 (file)
@@ -264,11 +264,6 @@ static int __devinit tegra_ahb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit tegra_ahb_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static const struct of_device_id tegra_ahb_of_match[] __devinitconst = {
        { .compatible = "nvidia,tegra30-ahb", },
        { .compatible = "nvidia,tegra20-ahb", },
@@ -277,7 +272,6 @@ static const struct of_device_id tegra_ahb_of_match[] __devinitconst = {
 
 static struct platform_driver tegra_ahb_driver = {
        .probe = tegra_ahb_probe,
-       .remove = __devexit_p(tegra_ahb_remove),
        .driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
index dcb8a6e4869249e4b26b405a9348f02113809ba6..4b01ab3d2c249328c810aaa03aec450d7f8d2822 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/wait.h>
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
+#include <scsi/scsi_scan.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -332,6 +333,7 @@ void wait_for_device_probe(void)
        /* wait for the known devices to complete their probing */
        wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);
        async_synchronize_full();
+       scsi_complete_async_scans();
 }
 EXPORT_SYMBOL_GPL(wait_for_device_probe);
 
index 765c3a28077af1998e264b932a9781afe633427d..d91a3a0b23258a516f352162a5d051df17959e80 100644 (file)
@@ -227,33 +227,24 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
 
 static int dev_rmdir(const char *name)
 {
-       struct nameidata nd;
+       struct path parent;
        struct dentry *dentry;
        int err;
 
-       err = kern_path_parent(name, &nd);
-       if (err)
-               return err;
-
-       mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-       dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
-       if (!IS_ERR(dentry)) {
-               if (dentry->d_inode) {
-                       if (dentry->d_inode->i_private == &thread)
-                               err = vfs_rmdir(nd.path.dentry->d_inode,
-                                               dentry);
-                       else
-                               err = -EPERM;
-               } else {
-                       err = -ENOENT;
-               }
-               dput(dentry);
+       dentry = kern_path_locked(name, &parent);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       if (dentry->d_inode) {
+               if (dentry->d_inode->i_private == &thread)
+                       err = vfs_rmdir(parent.dentry->d_inode, dentry);
+               else
+                       err = -EPERM;
        } else {
-               err = PTR_ERR(dentry);
+               err = -ENOENT;
        }
-
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-       path_put(&nd.path);
+       dput(dentry);
+       mutex_unlock(&parent.dentry->d_inode->i_mutex);
+       path_put(&parent);
        return err;
 }
 
@@ -305,50 +296,43 @@ static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *sta
 
 static int handle_remove(const char *nodename, struct device *dev)
 {
-       struct nameidata nd;
+       struct path parent;
        struct dentry *dentry;
-       struct kstat stat;
        int deleted = 1;
        int err;
 
-       err = kern_path_parent(nodename, &nd);
-       if (err)
-               return err;
+       dentry = kern_path_locked(nodename, &parent);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
 
-       mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-       dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
-       if (!IS_ERR(dentry)) {
-               if (dentry->d_inode) {
-                       err = vfs_getattr(nd.path.mnt, dentry, &stat);
-                       if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
-                               struct iattr newattrs;
-                               /*
-                                * before unlinking this node, reset permissions
-                                * of possible references like hardlinks
-                                */
-                               newattrs.ia_uid = 0;
-                               newattrs.ia_gid = 0;
-                               newattrs.ia_mode = stat.mode & ~0777;
-                               newattrs.ia_valid =
-                                       ATTR_UID|ATTR_GID|ATTR_MODE;
-                               mutex_lock(&dentry->d_inode->i_mutex);
-                               notify_change(dentry, &newattrs);
-                               mutex_unlock(&dentry->d_inode->i_mutex);
-                               err = vfs_unlink(nd.path.dentry->d_inode,
-                                                dentry);
-                               if (!err || err == -ENOENT)
-                                       deleted = 1;
-                       }
-               } else {
-                       err = -ENOENT;
+       if (dentry->d_inode) {
+               struct kstat stat;
+               err = vfs_getattr(parent.mnt, dentry, &stat);
+               if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
+                       struct iattr newattrs;
+                       /*
+                        * before unlinking this node, reset permissions
+                        * of possible references like hardlinks
+                        */
+                       newattrs.ia_uid = 0;
+                       newattrs.ia_gid = 0;
+                       newattrs.ia_mode = stat.mode & ~0777;
+                       newattrs.ia_valid =
+                               ATTR_UID|ATTR_GID|ATTR_MODE;
+                       mutex_lock(&dentry->d_inode->i_mutex);
+                       notify_change(dentry, &newattrs);
+                       mutex_unlock(&dentry->d_inode->i_mutex);
+                       err = vfs_unlink(parent.dentry->d_inode, dentry);
+                       if (!err || err == -ENOENT)
+                               deleted = 1;
                }
-               dput(dentry);
        } else {
-               err = PTR_ERR(dentry);
+               err = -ENOENT;
        }
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+       dput(dentry);
+       mutex_unlock(&parent.dentry->d_inode->i_mutex);
 
-       path_put(&nd.path);
+       path_put(&parent);
        if (deleted && strchr(nodename, '/'))
                delete_path(nodename);
        return err;
index 83aa694a8efe582f92365f193a07afcb5210b80d..ba3487c9835b67fa64daad5f6e23016f23a7f569 100644 (file)
@@ -75,19 +75,6 @@ static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
                                        start_latency_ns, "start");
 }
 
-static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
-{
-       return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
-                                       save_state_latency_ns, "state save");
-}
-
-static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
-{
-       return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
-                                       restore_state_latency_ns,
-                                       "state restore");
-}
-
 static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
 {
        bool ret = false;
@@ -139,6 +126,19 @@ static void genpd_set_active(struct generic_pm_domain *genpd)
                genpd->status = GPD_STATE_ACTIVE;
 }
 
+static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
+{
+       s64 usecs64;
+
+       if (!genpd->cpu_data)
+               return;
+
+       usecs64 = genpd->power_on_latency_ns;
+       do_div(usecs64, NSEC_PER_USEC);
+       usecs64 += genpd->cpu_data->saved_exit_latency;
+       genpd->cpu_data->idle_state->exit_latency = usecs64;
+}
+
 /**
  * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
@@ -146,7 +146,7 @@ static void genpd_set_active(struct generic_pm_domain *genpd)
  * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
-int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
        __releases(&genpd->lock) __acquires(&genpd->lock)
 {
        struct gpd_link *link;
@@ -176,6 +176,13 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
                return 0;
        }
 
+       if (genpd->cpu_data) {
+               cpuidle_pause_and_lock();
+               genpd->cpu_data->idle_state->disabled = true;
+               cpuidle_resume_and_unlock();
+               goto out;
+       }
+
        /*
         * The list is guaranteed not to change while the loop below is being
         * executed, unless one of the masters' .power_on() callbacks fiddles
@@ -215,6 +222,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
                if (elapsed_ns > genpd->power_on_latency_ns) {
                        genpd->power_on_latency_ns = elapsed_ns;
                        genpd->max_off_time_changed = true;
+                       genpd_recalc_cpu_exit_latency(genpd);
                        if (genpd->name)
                                pr_warning("%s: Power-on latency exceeded, "
                                        "new value %lld ns\n", genpd->name,
@@ -222,6 +230,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
                }
        }
 
+ out:
        genpd_set_active(genpd);
 
        return 0;
@@ -251,6 +260,19 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
 
 #ifdef CONFIG_PM_RUNTIME
 
+static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+       return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
+                                       save_state_latency_ns, "state save");
+}
+
+static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+       return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
+                                       restore_state_latency_ns,
+                                       "state restore");
+}
+
 static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
                                     unsigned long val, void *ptr)
 {
@@ -275,7 +297,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
 
                pdd = dev->power.subsys_data ?
                                dev->power.subsys_data->domain_data : NULL;
-               if (pdd) {
+               if (pdd && pdd->dev) {
                        to_gpd_data(pdd)->td.constraint_changed = true;
                        genpd = dev_to_genpd(dev);
                } else {
@@ -339,19 +361,16 @@ static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
 {
        struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
        struct device *dev = pdd->dev;
+       bool need_restore = gpd_data->need_restore;
 
-       if (!gpd_data->need_restore)
-               return;
-
+       gpd_data->need_restore = false;
        mutex_unlock(&genpd->lock);
 
        genpd_start_dev(genpd, dev);
-       genpd_restore_dev(genpd, dev);
-       genpd_stop_dev(genpd, dev);
+       if (need_restore)
+               genpd_restore_dev(genpd, dev);
 
        mutex_lock(&genpd->lock);
-
-       gpd_data->need_restore = false;
 }
 
 /**
@@ -458,6 +477,21 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
                }
        }
 
+       if (genpd->cpu_data) {
+               /*
+                * If cpu_data is set, cpuidle should turn the domain off when
+                * the CPU in it is idle.  In that case we don't decrement the
+                * subdomain counts of the master domains, so that power is not
+                * removed from the current domain prematurely as a result of
+                * cutting off the masters' power.
+                */
+               genpd->status = GPD_STATE_POWER_OFF;
+               cpuidle_pause_and_lock();
+               genpd->cpu_data->idle_state->disabled = false;
+               cpuidle_resume_and_unlock();
+               goto out;
+       }
+
        if (genpd->power_off) {
                ktime_t time_start;
                s64 elapsed_ns;
@@ -595,7 +629,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
 
        /* If power.irq_safe, the PM domain is never powered off. */
        if (dev->power.irq_safe)
-               goto out;
+               return genpd_start_dev(genpd, dev);
 
        mutex_lock(&genpd->lock);
        ret = __pm_genpd_poweron(genpd);
@@ -628,9 +662,6 @@ static int pm_genpd_runtime_resume(struct device *dev)
        wake_up_all(&genpd->status_wait_queue);
        mutex_unlock(&genpd->lock);
 
- out:
-       genpd_start_dev(genpd, dev);
-
        return 0;
 }
 
@@ -1235,6 +1266,27 @@ static void pm_genpd_complete(struct device *dev)
 
 #endif /* CONFIG_PM_SLEEP */
 
+static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev)
+{
+       struct generic_pm_domain_data *gpd_data;
+
+       gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+       if (!gpd_data)
+               return NULL;
+
+       mutex_init(&gpd_data->lock);
+       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+       dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+       return gpd_data;
+}
+
+static void __pm_genpd_free_dev_data(struct device *dev,
+                                    struct generic_pm_domain_data *gpd_data)
+{
+       dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+       kfree(gpd_data);
+}
+
 /**
  * __pm_genpd_add_device - Add a device to an I/O PM domain.
  * @genpd: PM domain to add the device to.
@@ -1244,7 +1296,7 @@ static void pm_genpd_complete(struct device *dev)
 int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
                          struct gpd_timing_data *td)
 {
-       struct generic_pm_domain_data *gpd_data;
+       struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
        struct pm_domain_data *pdd;
        int ret = 0;
 
@@ -1253,14 +1305,10 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
        if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
                return -EINVAL;
 
-       gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
-       if (!gpd_data)
+       gpd_data_new = __pm_genpd_alloc_dev_data(dev);
+       if (!gpd_data_new)
                return -ENOMEM;
 
-       mutex_init(&gpd_data->lock);
-       gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
-       dev_pm_qos_add_notifier(dev, &gpd_data->nb);
-
        genpd_acquire_lock(genpd);
 
        if (genpd->prepared_count > 0) {
@@ -1274,35 +1322,42 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
                        goto out;
                }
 
+       ret = dev_pm_get_subsys_data(dev);
+       if (ret)
+               goto out;
+
        genpd->device_count++;
        genpd->max_off_time_changed = true;
 
-       dev_pm_get_subsys_data(dev);
-
-       mutex_lock(&gpd_data->lock);
        spin_lock_irq(&dev->power.lock);
+
        dev->pm_domain = &genpd->domain;
-       dev->power.subsys_data->domain_data = &gpd_data->base;
-       gpd_data->base.dev = dev;
-       list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
-       gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
+       if (dev->power.subsys_data->domain_data) {
+               gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+       } else {
+               gpd_data = gpd_data_new;
+               dev->power.subsys_data->domain_data = &gpd_data->base;
+       }
+       gpd_data->refcount++;
        if (td)
                gpd_data->td = *td;
 
+       spin_unlock_irq(&dev->power.lock);
+
+       mutex_lock(&gpd_data->lock);
+       gpd_data->base.dev = dev;
+       list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+       gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
        gpd_data->td.constraint_changed = true;
        gpd_data->td.effective_constraint_ns = -1;
-       spin_unlock_irq(&dev->power.lock);
        mutex_unlock(&gpd_data->lock);
 
-       genpd_release_lock(genpd);
-
-       return 0;
-
  out:
        genpd_release_lock(genpd);
 
-       dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
-       kfree(gpd_data);
+       if (gpd_data != gpd_data_new)
+               __pm_genpd_free_dev_data(dev, gpd_data_new);
+
        return ret;
 }
 
@@ -1348,6 +1403,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 {
        struct generic_pm_domain_data *gpd_data;
        struct pm_domain_data *pdd;
+       bool remove = false;
        int ret = 0;
 
        dev_dbg(dev, "%s()\n", __func__);
@@ -1368,22 +1424,28 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
        genpd->max_off_time_changed = true;
 
        spin_lock_irq(&dev->power.lock);
+
        dev->pm_domain = NULL;
        pdd = dev->power.subsys_data->domain_data;
        list_del_init(&pdd->list_node);
-       dev->power.subsys_data->domain_data = NULL;
+       gpd_data = to_gpd_data(pdd);
+       if (--gpd_data->refcount == 0) {
+               dev->power.subsys_data->domain_data = NULL;
+               remove = true;
+       }
+
        spin_unlock_irq(&dev->power.lock);
 
-       gpd_data = to_gpd_data(pdd);
        mutex_lock(&gpd_data->lock);
        pdd->dev = NULL;
        mutex_unlock(&gpd_data->lock);
 
        genpd_release_lock(genpd);
 
-       dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
-       kfree(gpd_data);
        dev_pm_put_subsys_data(dev);
+       if (remove)
+               __pm_genpd_free_dev_data(dev, gpd_data);
+
        return 0;
 
  out:
@@ -1541,33 +1603,52 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
  * @dev: Device to add the callbacks to.
  * @ops: Set of callbacks to add.
  * @td: Timing data to add to the device along with the callbacks (optional).
+ *
+ * Every call to this routine should be balanced with a call to
+ * __pm_genpd_remove_callbacks() and they must not be nested.
  */
 int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops,
                           struct gpd_timing_data *td)
 {
-       struct pm_domain_data *pdd;
+       struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
        int ret = 0;
 
-       if (!(dev && dev->power.subsys_data && ops))
+       if (!(dev && ops))
                return -EINVAL;
 
+       gpd_data_new = __pm_genpd_alloc_dev_data(dev);
+       if (!gpd_data_new)
+               return -ENOMEM;
+
        pm_runtime_disable(dev);
        device_pm_lock();
 
-       pdd = dev->power.subsys_data->domain_data;
-       if (pdd) {
-               struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+       ret = dev_pm_get_subsys_data(dev);
+       if (ret)
+               goto out;
 
-               gpd_data->ops = *ops;
-               if (td)
-                       gpd_data->td = *td;
+       spin_lock_irq(&dev->power.lock);
+
+       if (dev->power.subsys_data->domain_data) {
+               gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
        } else {
-               ret = -EINVAL;
+               gpd_data = gpd_data_new;
+               dev->power.subsys_data->domain_data = &gpd_data->base;
        }
+       gpd_data->refcount++;
+       gpd_data->ops = *ops;
+       if (td)
+               gpd_data->td = *td;
+
+       spin_unlock_irq(&dev->power.lock);
 
+ out:
        device_pm_unlock();
        pm_runtime_enable(dev);
 
+       if (gpd_data != gpd_data_new)
+               __pm_genpd_free_dev_data(dev, gpd_data_new);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
@@ -1576,10 +1657,13 @@ EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
  * __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
  * @dev: Device to remove the callbacks from.
  * @clear_td: If set, clear the device's timing data too.
+ *
+ * This routine can only be called after pm_genpd_add_callbacks().
  */
 int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
 {
-       struct pm_domain_data *pdd;
+       struct generic_pm_domain_data *gpd_data = NULL;
+       bool remove = false;
        int ret = 0;
 
        if (!(dev && dev->power.subsys_data))
@@ -1588,24 +1672,118 @@ int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
        pm_runtime_disable(dev);
        device_pm_lock();
 
-       pdd = dev->power.subsys_data->domain_data;
-       if (pdd) {
-               struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+       spin_lock_irq(&dev->power.lock);
 
-               gpd_data->ops = (struct gpd_dev_ops){ 0 };
+       if (dev->power.subsys_data->domain_data) {
+               gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+               gpd_data->ops = (struct gpd_dev_ops){ NULL };
                if (clear_td)
                        gpd_data->td = (struct gpd_timing_data){ 0 };
+
+               if (--gpd_data->refcount == 0) {
+                       dev->power.subsys_data->domain_data = NULL;
+                       remove = true;
+               }
        } else {
                ret = -EINVAL;
        }
 
+       spin_unlock_irq(&dev->power.lock);
+
        device_pm_unlock();
        pm_runtime_enable(dev);
 
-       return ret;
+       if (ret)
+               return ret;
+
+       dev_pm_put_subsys_data(dev);
+       if (remove)
+               __pm_genpd_free_dev_data(dev, gpd_data);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
 
+int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
+{
+       struct cpuidle_driver *cpuidle_drv;
+       struct gpd_cpu_data *cpu_data;
+       struct cpuidle_state *idle_state;
+       int ret = 0;
+
+       if (IS_ERR_OR_NULL(genpd) || state < 0)
+               return -EINVAL;
+
+       genpd_acquire_lock(genpd);
+
+       if (genpd->cpu_data) {
+               ret = -EEXIST;
+               goto out;
+       }
+       cpu_data = kzalloc(sizeof(*cpu_data), GFP_KERNEL);
+       if (!cpu_data) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       cpuidle_drv = cpuidle_driver_ref();
+       if (!cpuidle_drv) {
+               ret = -ENODEV;
+               goto out;
+       }
+       if (cpuidle_drv->state_count <= state) {
+               ret = -EINVAL;
+               goto err;
+       }
+       idle_state = &cpuidle_drv->states[state];
+       if (!idle_state->disabled) {
+               ret = -EAGAIN;
+               goto err;
+       }
+       cpu_data->idle_state = idle_state;
+       cpu_data->saved_exit_latency = idle_state->exit_latency;
+       genpd->cpu_data = cpu_data;
+       genpd_recalc_cpu_exit_latency(genpd);
+
+ out:
+       genpd_release_lock(genpd);
+       return ret;
+
+ err:
+       cpuidle_driver_unref();
+       goto out;
+}
+
+int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+{
+       struct gpd_cpu_data *cpu_data;
+       struct cpuidle_state *idle_state;
+       int ret = 0;
+
+       if (IS_ERR_OR_NULL(genpd))
+               return -EINVAL;
+
+       genpd_acquire_lock(genpd);
+
+       cpu_data = genpd->cpu_data;
+       if (!cpu_data) {
+               ret = -ENODEV;
+               goto out;
+       }
+       idle_state = cpu_data->idle_state;
+       if (!idle_state->disabled) {
+               ret = -EAGAIN;
+               goto out;
+       }
+       idle_state->exit_latency = cpu_data->saved_exit_latency;
+       cpuidle_driver_unref();
+       genpd->cpu_data = NULL;
+       kfree(cpu_data);
+
+ out:
+       genpd_release_lock(genpd);
+       return ret;
+}
+
 /* Default device callbacks for generic PM domains. */
 
 /**
@@ -1615,16 +1793,24 @@ EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
 static int pm_genpd_default_save_state(struct device *dev)
 {
        int (*cb)(struct device *__dev);
-       struct device_driver *drv = dev->driver;
 
        cb = dev_gpd_data(dev)->ops.save_state;
        if (cb)
                return cb(dev);
 
-       if (drv && drv->pm && drv->pm->runtime_suspend)
-               return drv->pm->runtime_suspend(dev);
+       if (dev->type && dev->type->pm)
+               cb = dev->type->pm->runtime_suspend;
+       else if (dev->class && dev->class->pm)
+               cb = dev->class->pm->runtime_suspend;
+       else if (dev->bus && dev->bus->pm)
+               cb = dev->bus->pm->runtime_suspend;
+       else
+               cb = NULL;
 
-       return 0;
+       if (!cb && dev->driver && dev->driver->pm)
+               cb = dev->driver->pm->runtime_suspend;
+
+       return cb ? cb(dev) : 0;
 }
 
 /**
@@ -1634,16 +1820,24 @@ static int pm_genpd_default_save_state(struct device *dev)
 static int pm_genpd_default_restore_state(struct device *dev)
 {
        int (*cb)(struct device *__dev);
-       struct device_driver *drv = dev->driver;
 
        cb = dev_gpd_data(dev)->ops.restore_state;
        if (cb)
                return cb(dev);
 
-       if (drv && drv->pm && drv->pm->runtime_resume)
-               return drv->pm->runtime_resume(dev);
+       if (dev->type && dev->type->pm)
+               cb = dev->type->pm->runtime_resume;
+       else if (dev->class && dev->class->pm)
+               cb = dev->class->pm->runtime_resume;
+       else if (dev->bus && dev->bus->pm)
+               cb = dev->bus->pm->runtime_resume;
+       else
+               cb = NULL;
 
-       return 0;
+       if (!cb && dev->driver && dev->driver->pm)
+               cb = dev->driver->pm->runtime_resume;
+
+       return cb ? cb(dev) : 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
index 9cb845e49334c78d27a958066cf33dfc665c4ac1..0113adc310dccc4a62a325cccde4221f34c5ce7e 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/sched.h>
 #include <linux/async.h>
 #include <linux/suspend.h>
-
+#include <linux/cpuidle.h>
 #include "../base.h"
 #include "power.h"
 
@@ -45,10 +45,10 @@ typedef int (*pm_callback_t)(struct device *);
  */
 
 LIST_HEAD(dpm_list);
-LIST_HEAD(dpm_prepared_list);
-LIST_HEAD(dpm_suspended_list);
-LIST_HEAD(dpm_late_early_list);
-LIST_HEAD(dpm_noirq_list);
+static LIST_HEAD(dpm_prepared_list);
+static LIST_HEAD(dpm_suspended_list);
+static LIST_HEAD(dpm_late_early_list);
+static LIST_HEAD(dpm_noirq_list);
 
 struct suspend_stats suspend_stats;
 static DEFINE_MUTEX(dpm_list_mtx);
@@ -166,7 +166,7 @@ static ktime_t initcall_debug_start(struct device *dev)
 {
        ktime_t calltime = ktime_set(0, 0);
 
-       if (initcall_debug) {
+       if (pm_print_times_enabled) {
                pr_info("calling  %s+ @ %i, parent: %s\n",
                        dev_name(dev), task_pid_nr(current),
                        dev->parent ? dev_name(dev->parent) : "none");
@@ -181,7 +181,7 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime,
 {
        ktime_t delta, rettime;
 
-       if (initcall_debug) {
+       if (pm_print_times_enabled) {
                rettime = ktime_get();
                delta = ktime_sub(rettime, calltime);
                pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
@@ -467,6 +467,7 @@ static void dpm_resume_noirq(pm_message_t state)
        mutex_unlock(&dpm_list_mtx);
        dpm_show_time(starttime, state, "noirq");
        resume_device_irqs();
+       cpuidle_resume();
 }
 
 /**
@@ -867,6 +868,7 @@ static int dpm_suspend_noirq(pm_message_t state)
        ktime_t starttime = ktime_get();
        int error = 0;
 
+       cpuidle_pause();
        suspend_device_irqs();
        mutex_lock(&dpm_list_mtx);
        while (!list_empty(&dpm_late_early_list)) {
@@ -989,8 +991,16 @@ static int dpm_suspend_late(pm_message_t state)
 int dpm_suspend_end(pm_message_t state)
 {
        int error = dpm_suspend_late(state);
+       if (error)
+               return error;
+
+       error = dpm_suspend_noirq(state);
+       if (error) {
+               dpm_resume_early(state);
+               return error;
+       }
 
-       return error ? : dpm_suspend_noirq(state);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(dpm_suspend_end);
 
index fd849a2c4fa8fdaa4ae3ac10a8ce853b9e14bec7..74a67e0019a2d246820ccb2858399bca193ff789 100644 (file)
@@ -462,7 +462,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
 static void __dev_pm_qos_drop_user_request(struct device *dev)
 {
        dev_pm_qos_remove_request(dev->power.pq_req);
-       dev->power.pq_req = 0;
+       dev->power.pq_req = NULL;
 }
 
 /**
index 48be2ad4dd2cb4f54c592bfdcaf99f2aa509ca8c..b91dc6f1e91476484584b5eb08f9dbb4b8811030 100644 (file)
@@ -474,6 +474,8 @@ static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL);
 
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+
 static ssize_t async_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
@@ -500,6 +502,8 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
 }
 
 static DEVICE_ATTR(async, 0644, async_show, async_store);
+
+#endif
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 
 static struct attribute *power_attrs[] = {
index b986b8660b0c4e72da132a0a32ab2960ca99e183..80f9ab9c3aa4b7eba89b436d0dcd6a96b3623558 100644 (file)
@@ -95,6 +95,9 @@ struct regmap {
 
        /* if set, converts bulk rw to single rw */
        bool use_single_rw;
+
+       struct rb_root range_tree;
+       void *selector_work_buf;        /* Scratch buffer used for selector */
 };
 
 struct regcache_ops {
@@ -115,6 +118,20 @@ bool regmap_precious(struct regmap *map, unsigned int reg);
 int _regmap_write(struct regmap *map, unsigned int reg,
                  unsigned int val);
 
+struct regmap_range_node {
+       struct rb_node node;
+
+       unsigned int range_min;
+       unsigned int range_max;
+
+       unsigned int selector_reg;
+       unsigned int selector_mask;
+       int selector_shift;
+
+       unsigned int window_start;
+       unsigned int window_len;
+};
+
 #ifdef CONFIG_DEBUG_FS
 extern void regmap_debugfs_initcall(void);
 extern void regmap_debugfs_init(struct regmap *map, const char *name);
index 4fac4b9be88f7ca5b7144396e5908b5b8f1bb593..a89734621e517e367b15b925ccd507da04daca89 100644 (file)
@@ -24,14 +24,18 @@ struct regmap_irq_chip_data {
        struct mutex lock;
 
        struct regmap *map;
-       struct regmap_irq_chip *chip;
+       const struct regmap_irq_chip *chip;
 
        int irq_base;
        struct irq_domain *domain;
 
+       int irq;
+       int wake_count;
+
        unsigned int *status_buf;
        unsigned int *mask_buf;
        unsigned int *mask_buf_def;
+       unsigned int *wake_buf;
 
        unsigned int irq_reg_stride;
 };
@@ -71,6 +75,16 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                                d->chip->mask_base + (i * map->reg_stride));
        }
 
+       /* If we've changed our wakeup count propagate it to the parent */
+       if (d->wake_count < 0)
+               for (i = d->wake_count; i < 0; i++)
+                       irq_set_irq_wake(d->irq, 0);
+       else if (d->wake_count > 0)
+               for (i = 0; i < d->wake_count; i++)
+                       irq_set_irq_wake(d->irq, 1);
+
+       d->wake_count = 0;
+
        mutex_unlock(&d->lock);
 }
 
@@ -92,18 +106,41 @@ static void regmap_irq_disable(struct irq_data *data)
        d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
 }
 
+static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+       struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+       struct regmap *map = d->map;
+       const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
+
+       if (!d->chip->wake_base)
+               return -EINVAL;
+
+       if (on) {
+               d->wake_buf[irq_data->reg_offset / map->reg_stride]
+                       &= ~irq_data->mask;
+               d->wake_count++;
+       } else {
+               d->wake_buf[irq_data->reg_offset / map->reg_stride]
+                       |= irq_data->mask;
+               d->wake_count--;
+       }
+
+       return 0;
+}
+
 static struct irq_chip regmap_irq_chip = {
        .name                   = "regmap",
        .irq_bus_lock           = regmap_irq_lock,
        .irq_bus_sync_unlock    = regmap_irq_sync_unlock,
        .irq_disable            = regmap_irq_disable,
        .irq_enable             = regmap_irq_enable,
+       .irq_set_wake           = regmap_irq_set_wake,
 };
 
 static irqreturn_t regmap_irq_thread(int irq, void *d)
 {
        struct regmap_irq_chip_data *data = d;
-       struct regmap_irq_chip *chip = data->chip;
+       const struct regmap_irq_chip *chip = data->chip;
        struct regmap *map = data->map;
        int ret, i;
        bool handled = false;
@@ -195,7 +232,7 @@ static struct irq_domain_ops regmap_domain_ops = {
  * register values used by the IRQ controller over suspend and resume.
  */
 int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
-                       int irq_base, struct regmap_irq_chip *chip,
+                       int irq_base, const struct regmap_irq_chip *chip,
                        struct regmap_irq_chip_data **data)
 {
        struct regmap_irq_chip_data *d;
@@ -240,6 +277,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        if (!d->mask_buf_def)
                goto err_alloc;
 
+       if (chip->wake_base) {
+               d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+                                     GFP_KERNEL);
+               if (!d->wake_buf)
+                       goto err_alloc;
+       }
+
+       d->irq = irq;
        d->map = map;
        d->chip = chip;
        d->irq_base = irq_base;
@@ -294,6 +339,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 err_domain:
        /* Should really dispose of the domain but... */
 err_alloc:
+       kfree(d->wake_buf);
        kfree(d->mask_buf_def);
        kfree(d->mask_buf);
        kfree(d->status_buf);
@@ -315,6 +361,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 
        free_irq(irq, d);
        /* We should unmap the domain but... */
+       kfree(d->wake_buf);
        kfree(d->mask_buf_def);
        kfree(d->mask_buf);
        kfree(d->status_buf);
@@ -346,6 +393,10 @@ EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);
  */
 int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
 {
+       /* Handle holes in the IRQ list */
+       if (!data->chip->irqs[irq].mask)
+               return -EINVAL;
+
        return irq_create_mapping(data->domain, irq);
 }
 EXPORT_SYMBOL_GPL(regmap_irq_get_virq);
index febd6de6c8ac20c3b4a5c86ac903f5c909461f4f..f05fc74dd84a5f46b8cb32ed3943972fffe056e7 100644 (file)
@@ -37,7 +37,7 @@ static int regmap_mmio_gather_write(void *context,
 
        BUG_ON(reg_size != 4);
 
-       offset = be32_to_cpup(reg);
+       offset = *(u32 *)reg;
 
        while (val_size) {
                switch (ctx->val_bytes) {
@@ -45,14 +45,14 @@ static int regmap_mmio_gather_write(void *context,
                        writeb(*(u8 *)val, ctx->regs + offset);
                        break;
                case 2:
-                       writew(be16_to_cpup(val), ctx->regs + offset);
+                       writew(*(u16 *)val, ctx->regs + offset);
                        break;
                case 4:
-                       writel(be32_to_cpup(val), ctx->regs + offset);
+                       writel(*(u32 *)val, ctx->regs + offset);
                        break;
 #ifdef CONFIG_64BIT
                case 8:
-                       writeq(be64_to_cpup(val), ctx->regs + offset);
+                       writeq(*(u64 *)val, ctx->regs + offset);
                        break;
 #endif
                default:
@@ -83,7 +83,7 @@ static int regmap_mmio_read(void *context,
 
        BUG_ON(reg_size != 4);
 
-       offset = be32_to_cpup(reg);
+       offset = *(u32 *)reg;
 
        while (val_size) {
                switch (ctx->val_bytes) {
@@ -91,14 +91,14 @@ static int regmap_mmio_read(void *context,
                        *(u8 *)val = readb(ctx->regs + offset);
                        break;
                case 2:
-                       *(u16 *)val = cpu_to_be16(readw(ctx->regs + offset));
+                       *(u16 *)val = readw(ctx->regs + offset);
                        break;
                case 4:
-                       *(u32 *)val = cpu_to_be32(readl(ctx->regs + offset));
+                       *(u32 *)val = readl(ctx->regs + offset);
                        break;
 #ifdef CONFIG_64BIT
                case 8:
-                       *(u64 *)val = cpu_to_be32(readq(ctx->regs + offset));
+                       *(u64 *)val = readq(ctx->regs + offset);
                        break;
 #endif
                default:
@@ -124,9 +124,11 @@ static struct regmap_bus regmap_mmio = {
        .gather_write = regmap_mmio_gather_write,
        .read = regmap_mmio_read,
        .free_context = regmap_mmio_free_context,
+       .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+       .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
 };
 
-struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
+static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
                                        const struct regmap_config *config)
 {
        struct regmap_mmio_context *ctx;
@@ -162,7 +164,15 @@ struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs,
        if (config->reg_stride < min_stride)
                return ERR_PTR(-EINVAL);
 
-       ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
+       switch (config->reg_format_endian) {
+       case REGMAP_ENDIAN_DEFAULT:
+       case REGMAP_ENDIAN_NATIVE:
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return ERR_PTR(-ENOMEM);
 
index c89aa01fb1de8262838998dc68f778d5d7473d91..c241ae2f2f10b91e8998e5b657d5f739cc0c0b7b 100644 (file)
 #include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
+#include <linux/rbtree.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/regmap.h>
 
 #include "internal.h"
 
+/*
+ * Sometimes for failures during very early init the trace
+ * infrastructure isn't available early enough to be used.  For this
+ * sort of problem defining LOG_DEVICE will add printks for basic
+ * register I/O on a specific device.
+ */
+#undef LOG_DEVICE
+
+static int _regmap_update_bits(struct regmap *map, unsigned int reg,
+                              unsigned int mask, unsigned int val,
+                              bool *change);
+
 bool regmap_writeable(struct regmap *map, unsigned int reg)
 {
        if (map->max_register && reg > map->max_register)
@@ -119,13 +132,19 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
        b[0] = val << shift;
 }
 
-static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift)
 {
        __be16 *b = buf;
 
        b[0] = cpu_to_be16(val << shift);
 }
 
+static void regmap_format_16_native(void *buf, unsigned int val,
+                                   unsigned int shift)
+{
+       *(u16 *)buf = val << shift;
+}
+
 static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
 {
        u8 *b = buf;
@@ -137,13 +156,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
        b[2] = val;
 }
 
-static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift)
 {
        __be32 *b = buf;
 
        b[0] = cpu_to_be32(val << shift);
 }
 
+static void regmap_format_32_native(void *buf, unsigned int val,
+                                   unsigned int shift)
+{
+       *(u32 *)buf = val << shift;
+}
+
 static unsigned int regmap_parse_8(void *buf)
 {
        u8 *b = buf;
@@ -151,7 +176,7 @@ static unsigned int regmap_parse_8(void *buf)
        return b[0];
 }
 
-static unsigned int regmap_parse_16(void *buf)
+static unsigned int regmap_parse_16_be(void *buf)
 {
        __be16 *b = buf;
 
@@ -160,6 +185,11 @@ static unsigned int regmap_parse_16(void *buf)
        return b[0];
 }
 
+static unsigned int regmap_parse_16_native(void *buf)
+{
+       return *(u16 *)buf;
+}
+
 static unsigned int regmap_parse_24(void *buf)
 {
        u8 *b = buf;
@@ -170,7 +200,7 @@ static unsigned int regmap_parse_24(void *buf)
        return ret;
 }
 
-static unsigned int regmap_parse_32(void *buf)
+static unsigned int regmap_parse_32_be(void *buf)
 {
        __be32 *b = buf;
 
@@ -179,6 +209,11 @@ static unsigned int regmap_parse_32(void *buf)
        return b[0];
 }
 
+static unsigned int regmap_parse_32_native(void *buf)
+{
+       return *(u32 *)buf;
+}
+
 static void regmap_lock_mutex(struct regmap *map)
 {
        mutex_lock(&map->mutex);
@@ -208,6 +243,67 @@ static void dev_get_regmap_release(struct device *dev, void *res)
         */
 }
 
+static bool _regmap_range_add(struct regmap *map,
+                             struct regmap_range_node *data)
+{
+       struct rb_root *root = &map->range_tree;
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+       while (*new) {
+               struct regmap_range_node *this =
+                       container_of(*new, struct regmap_range_node, node);
+
+               parent = *new;
+               if (data->range_max < this->range_min)
+                       new = &((*new)->rb_left);
+               else if (data->range_min > this->range_max)
+                       new = &((*new)->rb_right);
+               else
+                       return false;
+       }
+
+       rb_link_node(&data->node, parent, new);
+       rb_insert_color(&data->node, root);
+
+       return true;
+}
+
+static struct regmap_range_node *_regmap_range_lookup(struct regmap *map,
+                                                     unsigned int reg)
+{
+       struct rb_node *node = map->range_tree.rb_node;
+
+       while (node) {
+               struct regmap_range_node *this =
+                       container_of(node, struct regmap_range_node, node);
+
+               if (reg < this->range_min)
+                       node = node->rb_left;
+               else if (reg > this->range_max)
+                       node = node->rb_right;
+               else
+                       return this;
+       }
+
+       return NULL;
+}
+
+static void regmap_range_exit(struct regmap *map)
+{
+       struct rb_node *next;
+       struct regmap_range_node *range_node;
+
+       next = rb_first(&map->range_tree);
+       while (next) {
+               range_node = rb_entry(next, struct regmap_range_node, node);
+               next = rb_next(&range_node->node);
+               rb_erase(&range_node->node, &map->range_tree);
+               kfree(range_node);
+       }
+
+       kfree(map->selector_work_buf);
+}
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -227,6 +323,8 @@ struct regmap *regmap_init(struct device *dev,
 {
        struct regmap *map, **m;
        int ret = -EINVAL;
+       enum regmap_endian reg_endian, val_endian;
+       int i, j;
 
        if (!bus || !config)
                goto err;
@@ -275,6 +373,18 @@ struct regmap *regmap_init(struct device *dev,
                map->read_flag_mask = bus->read_flag_mask;
        }
 
+       reg_endian = config->reg_format_endian;
+       if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+               reg_endian = bus->reg_format_endian_default;
+       if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+               reg_endian = REGMAP_ENDIAN_BIG;
+
+       val_endian = config->val_format_endian;
+       if (val_endian == REGMAP_ENDIAN_DEFAULT)
+               val_endian = bus->val_format_endian_default;
+       if (val_endian == REGMAP_ENDIAN_DEFAULT)
+               val_endian = REGMAP_ENDIAN_BIG;
+
        switch (config->reg_bits + map->reg_shift) {
        case 2:
                switch (config->val_bits) {
@@ -321,11 +431,29 @@ struct regmap *regmap_init(struct device *dev,
                break;
 
        case 16:
-               map->format.format_reg = regmap_format_16;
+               switch (reg_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_reg = regmap_format_16_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_reg = regmap_format_16_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
 
        case 32:
-               map->format.format_reg = regmap_format_32;
+               switch (reg_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_reg = regmap_format_32_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_reg = regmap_format_32_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
 
        default:
@@ -338,21 +466,47 @@ struct regmap *regmap_init(struct device *dev,
                map->format.parse_val = regmap_parse_8;
                break;
        case 16:
-               map->format.format_val = regmap_format_16;
-               map->format.parse_val = regmap_parse_16;
+               switch (val_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_val = regmap_format_16_be;
+                       map->format.parse_val = regmap_parse_16_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_val = regmap_format_16_native;
+                       map->format.parse_val = regmap_parse_16_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
        case 24:
+               if (val_endian != REGMAP_ENDIAN_BIG)
+                       goto err_map;
                map->format.format_val = regmap_format_24;
                map->format.parse_val = regmap_parse_24;
                break;
        case 32:
-               map->format.format_val = regmap_format_32;
-               map->format.parse_val = regmap_parse_32;
+               switch (val_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_val = regmap_format_32_be;
+                       map->format.parse_val = regmap_parse_32_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_val = regmap_format_32_native;
+                       map->format.parse_val = regmap_parse_32_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
        }
 
-       if (map->format.format_write)
+       if (map->format.format_write) {
+               if ((reg_endian != REGMAP_ENDIAN_BIG) ||
+                   (val_endian != REGMAP_ENDIAN_BIG))
+                       goto err_map;
                map->use_single_rw = true;
+       }
 
        if (!map->format.format_write &&
            !(map->format.format_reg && map->format.format_val))
@@ -364,27 +518,88 @@ struct regmap *regmap_init(struct device *dev,
                goto err_map;
        }
 
-       regmap_debugfs_init(map, config->name);
+       map->range_tree = RB_ROOT;
+       for (i = 0; i < config->n_ranges; i++) {
+               const struct regmap_range_cfg *range_cfg = &config->ranges[i];
+               struct regmap_range_node *new;
+
+               /* Sanity check */
+               if (range_cfg->range_max < range_cfg->range_min ||
+                   range_cfg->range_max > map->max_register ||
+                   range_cfg->selector_reg > map->max_register ||
+                   range_cfg->window_len == 0)
+                       goto err_range;
+
+               /* Make sure, that this register range has no selector
+                  or data window within its boundary */
+               for (j = 0; j < config->n_ranges; j++) {
+                       unsigned sel_reg = config->ranges[j].selector_reg;
+                       unsigned win_min = config->ranges[j].window_start;
+                       unsigned win_max = win_min +
+                                          config->ranges[j].window_len - 1;
+
+                       if (range_cfg->range_min <= sel_reg &&
+                           sel_reg <= range_cfg->range_max) {
+                               goto err_range;
+                       }
+
+                       if (!(win_max < range_cfg->range_min ||
+                             win_min > range_cfg->range_max)) {
+                               goto err_range;
+                       }
+               }
+
+               new = kzalloc(sizeof(*new), GFP_KERNEL);
+               if (new == NULL) {
+                       ret = -ENOMEM;
+                       goto err_range;
+               }
+
+               new->range_min = range_cfg->range_min;
+               new->range_max = range_cfg->range_max;
+               new->selector_reg = range_cfg->selector_reg;
+               new->selector_mask = range_cfg->selector_mask;
+               new->selector_shift = range_cfg->selector_shift;
+               new->window_start = range_cfg->window_start;
+               new->window_len = range_cfg->window_len;
+
+               if (_regmap_range_add(map, new) == false) {
+                       kfree(new);
+                       goto err_range;
+               }
+
+               if (map->selector_work_buf == NULL) {
+                       map->selector_work_buf =
+                               kzalloc(map->format.buf_size, GFP_KERNEL);
+                       if (map->selector_work_buf == NULL) {
+                               ret = -ENOMEM;
+                               goto err_range;
+                       }
+               }
+       }
 
        ret = regcache_init(map, config);
        if (ret < 0)
-               goto err_debugfs;
+               goto err_range;
+
+       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) {
                ret = -ENOMEM;
-               goto err_cache;
+               goto err_debugfs;
        }
        *m = map;
        devres_add(dev, m);
 
        return map;
 
-err_cache:
-       regcache_exit(map);
 err_debugfs:
        regmap_debugfs_exit(map);
+       regcache_exit(map);
+err_range:
+       regmap_range_exit(map);
        kfree(map->work_buf);
 err_map:
        kfree(map);
@@ -481,6 +696,7 @@ void regmap_exit(struct regmap *map)
 {
        regcache_exit(map);
        regmap_debugfs_exit(map);
+       regmap_range_exit(map);
        if (map->bus->free_context)
                map->bus->free_context(map->bus_context);
        kfree(map->work_buf);
@@ -526,6 +742,57 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name)
 }
 EXPORT_SYMBOL_GPL(dev_get_regmap);
 
+static int _regmap_select_page(struct regmap *map, unsigned int *reg,
+                              unsigned int val_num)
+{
+       struct regmap_range_node *range;
+       void *orig_work_buf;
+       unsigned int win_offset;
+       unsigned int win_page;
+       bool page_chg;
+       int ret;
+
+       range = _regmap_range_lookup(map, *reg);
+       if (range) {
+               win_offset = (*reg - range->range_min) % range->window_len;
+               win_page = (*reg - range->range_min) / range->window_len;
+
+               if (val_num > 1) {
+                       /* Bulk write shouldn't cross range boundary */
+                       if (*reg + val_num - 1 > range->range_max)
+                               return -EINVAL;
+
+                       /* ... or single page boundary */
+                       if (val_num > range->window_len - win_offset)
+                               return -EINVAL;
+               }
+
+               /* It is possible to have selector register inside data window.
+                  In that case, selector register is located on every page and
+                  it needs no page switching, when accessed alone. */
+               if (val_num > 1 ||
+                   range->window_start + win_offset != range->selector_reg) {
+                       /* Use separate work_buf during page switching */
+                       orig_work_buf = map->work_buf;
+                       map->work_buf = map->selector_work_buf;
+
+                       ret = _regmap_update_bits(map, range->selector_reg,
+                                       range->selector_mask,
+                                       win_page << range->selector_shift,
+                                       &page_chg);
+
+                       map->work_buf = orig_work_buf;
+
+                       if (ret < 0)
+                               return ret;
+               }
+
+               *reg = range->window_start + win_offset;
+       }
+
+       return 0;
+}
+
 static int _regmap_raw_write(struct regmap *map, unsigned int reg,
                             const void *val, size_t val_len)
 {
@@ -563,6 +830,10 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
                }
        }
 
+       ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
+       if (ret < 0)
+               return ret;
+
        map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
        u8[0] |= map->write_flag_mask;
@@ -623,9 +894,18 @@ int _regmap_write(struct regmap *map, unsigned int reg,
                }
        }
 
+#ifdef LOG_DEVICE
+       if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
+               dev_info(map->dev, "%x <= %x\n", reg, val);
+#endif
+
        trace_regmap_reg_write(map->dev, reg, val);
 
        if (map->format.format_write) {
+               ret = _regmap_select_page(map, &reg, 1);
+               if (ret < 0)
+                       return ret;
+
                map->format.format_write(map, reg, val);
 
                trace_regmap_hw_write_start(map->dev, reg, 1);
@@ -783,6 +1063,10 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
        u8 *u8 = map->work_buf;
        int ret;
 
+       ret = _regmap_select_page(map, &reg, val_len / map->format.val_bytes);
+       if (ret < 0)
+               return ret;
+
        map->format.format_reg(map->work_buf, reg, map->reg_shift);
 
        /*
@@ -826,6 +1110,12 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
        ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
        if (ret == 0) {
                *val = map->format.parse_val(map->work_buf);
+
+#ifdef LOG_DEVICE
+               if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
+                       dev_info(map->dev, "%x => %x\n", reg, *val);
+#endif
+
                trace_regmap_reg_read(map->dev, reg, *val);
        }
 
@@ -982,11 +1272,9 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
        int ret;
        unsigned int tmp, orig;
 
-       map->lock(map);
-
        ret = _regmap_read(map, reg, &orig);
        if (ret != 0)
-               goto out;
+               return ret;
 
        tmp = orig & ~mask;
        tmp |= val & mask;
@@ -998,9 +1286,6 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
                *change = false;
        }
 
-out:
-       map->unlock(map);
-
        return ret;
 }
 
@@ -1018,7 +1303,13 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
                       unsigned int mask, unsigned int val)
 {
        bool change;
-       return _regmap_update_bits(map, reg, mask, val, &change);
+       int ret;
+
+       map->lock(map);
+       ret = _regmap_update_bits(map, reg, mask, val, &change);
+       map->unlock(map);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits);
 
@@ -1038,7 +1329,12 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
                             unsigned int mask, unsigned int val,
                             bool *change)
 {
-       return _regmap_update_bits(map, reg, mask, val, change);
+       int ret;
+
+       map->lock(map);
+       ret = _regmap_update_bits(map, reg, mask, val, change);
+       map->unlock(map);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits_check);
 
index b5c5ff53cb57f74e89cc59bad8ca6e29df5e1db5..fcb956bb4b4c525875f961e7c2398b20c35723f4 100644 (file)
@@ -1475,10 +1475,17 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
                first_word = 0;
                spin_lock_irq(&b->bm_lock);
        }
-
        /* last page (respectively only page, for first page == last page) */
        last_word = MLPP(el >> LN2_BPL);
-       bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
+
+       /* consider bitmap->bm_bits = 32768, bitmap->bm_number_of_pages = 1. (or multiples).
+        * ==> e = 32767, el = 32768, last_page = 2,
+        * and now last_word = 0.
+        * We do not want to touch last_page in this case,
+        * as we did not allocate it, it is not present in bitmap->bm_pages.
+        */
+       if (last_word)
+               bm_set_full_words_within_one_page(mdev->bitmap, last_page, first_word, last_word);
 
        /* possibly trailing bits.
         * example: (e & 63) == 63, el will be e+1.
index 9c5c84946b056792fa45d99051bd5c28750db7e1..8e93a6ac9bb65e3497f53c92723a67429ffdf946 100644 (file)
@@ -472,12 +472,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
                req->rq_state |= RQ_LOCAL_COMPLETED;
                req->rq_state &= ~RQ_LOCAL_PENDING;
 
-               D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+               if (req->rq_state & RQ_LOCAL_ABORTED) {
+                       _req_may_be_done(req, m);
+                       break;
+               }
 
                __drbd_chk_io_error(mdev, false);
 
        goto_queue_for_net_read:
 
+               D_ASSERT(!(req->rq_state & RQ_NET_MASK));
+
                /* no point in retrying if there is no good remote data,
                 * or we have no connection. */
                if (mdev->state.pdsk != D_UP_TO_DATE) {
@@ -765,6 +770,40 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s
        return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
 }
 
+static void maybe_pull_ahead(struct drbd_conf *mdev)
+{
+       int congested = 0;
+
+       /* If I don't even have good local storage, we can not reasonably try
+        * to pull ahead of the peer. We also need the local reference to make
+        * sure mdev->act_log is there.
+        * Note: caller has to make sure that net_conf is there.
+        */
+       if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+               return;
+
+       if (mdev->net_conf->cong_fill &&
+           atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
+               dev_info(DEV, "Congestion-fill threshold reached\n");
+               congested = 1;
+       }
+
+       if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
+               dev_info(DEV, "Congestion-extents threshold reached\n");
+               congested = 1;
+       }
+
+       if (congested) {
+               queue_barrier(mdev); /* last barrier, after mirrored writes */
+
+               if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
+                       _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
+               else  /*mdev->net_conf->on_congestion == OC_DISCONNECT */
+                       _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
+       }
+       put_ldev(mdev);
+}
+
 static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
 {
        const int rw = bio_rw(bio);
@@ -972,29 +1011,8 @@ allocate_barrier:
                _req_mod(req, queue_for_send_oos);
 
        if (remote &&
-           mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) {
-               int congested = 0;
-
-               if (mdev->net_conf->cong_fill &&
-                   atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
-                       dev_info(DEV, "Congestion-fill threshold reached\n");
-                       congested = 1;
-               }
-
-               if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
-                       dev_info(DEV, "Congestion-extents threshold reached\n");
-                       congested = 1;
-               }
-
-               if (congested) {
-                       queue_barrier(mdev); /* last barrier, after mirrored writes */
-
-                       if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
-                               _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
-                       else  /*mdev->net_conf->on_congestion == OC_DISCONNECT */
-                               _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
-               }
-       }
+           mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96)
+               maybe_pull_ahead(mdev);
 
        spin_unlock_irq(&mdev->req_lock);
        kfree(b); /* if someone else has beaten us to it... */
index cce7df367b793d111ef875bd5cd30a6f5e08782c..553f43a90953cab40f421658ecb37fa9c20c8c54 100644 (file)
@@ -671,6 +671,7 @@ static void __reschedule_timeout(int drive, const char *message)
 
        if (drive == current_reqD)
                drive = current_drive;
+       __cancel_delayed_work(&fd_timeout);
 
        if (drive < 0 || drive >= N_DRIVE) {
                delay = 20UL * HZ;
index bbca966f8f66a20b04f62ac01ff41cd5ef18c037..3bba65510d23afdf39070f7d23552e8e15e27af2 100644 (file)
@@ -1597,14 +1597,12 @@ static int loop_add(struct loop_device **l, int i)
        struct gendisk *disk;
        int err;
 
+       err = -ENOMEM;
        lo = kzalloc(sizeof(*lo), GFP_KERNEL);
-       if (!lo) {
-               err = -ENOMEM;
+       if (!lo)
                goto out;
-       }
 
-       err = idr_pre_get(&loop_index_idr, GFP_KERNEL);
-       if (err < 0)
+       if (!idr_pre_get(&loop_index_idr, GFP_KERNEL))
                goto out_free_dev;
 
        if (i >= 0) {
index 76fa3deaee84059d4431f7763981311210f16f06..1788f491e0fb50e13cefb2f81c286d41721e75ef 100644 (file)
@@ -780,9 +780,9 @@ static const struct block_device_operations mg_disk_ops = {
        .getgeo = mg_getgeo
 };
 
-static int mg_suspend(struct platform_device *plat_dev, pm_message_t state)
+static int mg_suspend(struct device *dev)
 {
-       struct mg_drv_data *prv_data = plat_dev->dev.platform_data;
+       struct mg_drv_data *prv_data = dev->platform_data;
        struct mg_host *host = prv_data->host;
 
        if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD))
@@ -804,9 +804,9 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state)
        return 0;
 }
 
-static int mg_resume(struct platform_device *plat_dev)
+static int mg_resume(struct device *dev)
 {
-       struct mg_drv_data *prv_data = plat_dev->dev.platform_data;
+       struct mg_drv_data *prv_data = dev->platform_data;
        struct mg_host *host = prv_data->host;
 
        if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD))
@@ -825,6 +825,8 @@ static int mg_resume(struct platform_device *plat_dev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(mg_pm, mg_suspend, mg_resume);
+
 static int mg_probe(struct platform_device *plat_dev)
 {
        struct mg_host *host;
@@ -1074,11 +1076,10 @@ static int mg_remove(struct platform_device *plat_dev)
 static struct platform_driver mg_disk_driver = {
        .probe = mg_probe,
        .remove = mg_remove,
-       .suspend = mg_suspend,
-       .resume = mg_resume,
        .driver = {
                .name = MG_DEV_NAME,
                .owner = THIS_MODULE,
+               .pm = &mg_pm,
        }
 };
 
index 264bc77dcb911c7030c787d3ad87cd79b654ce81..a8fddeb3d638ebcdf9a0191beda816d8f1338ccd 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/kthread.h>
 #include <../drivers/ata/ahci.h>
 #include <linux/export.h>
+#include <linux/debugfs.h>
 #include "mtip32xx.h"
 
 #define HW_CMD_SLOT_SZ         (MTIP_MAX_COMMAND_SLOTS * 32)
@@ -85,6 +86,7 @@ static int instance;
  * allocated in mtip_init().
  */
 static int mtip_major;
+static struct dentry *dfs_parent;
 
 static DEFINE_SPINLOCK(rssd_index_lock);
 static DEFINE_IDA(rssd_index_ida);
@@ -2546,7 +2548,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
 }
 
 /*
- * Sysfs register/status dump.
+ * Sysfs status dump.
  *
  * @dev  Pointer to the device structure, passed by the kernrel.
  * @attr Pointer to the device_attribute structure passed by the kernel.
@@ -2555,45 +2557,68 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
  * return value
  *     The size, in bytes, of the data copied into buf.
  */
-static ssize_t mtip_hw_show_registers(struct device *dev,
+static ssize_t mtip_hw_show_status(struct device *dev,
                                struct device_attribute *attr,
                                char *buf)
 {
-       u32 group_allocated;
        struct driver_data *dd = dev_to_disk(dev)->private_data;
        int size = 0;
+
+       if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
+               size += sprintf(buf, "%s", "thermal_shutdown\n");
+       else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
+               size += sprintf(buf, "%s", "write_protect\n");
+       else
+               size += sprintf(buf, "%s", "online\n");
+
+       return size;
+}
+
+static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
+
+static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
+                                 size_t len, loff_t *offset)
+{
+       struct driver_data *dd =  (struct driver_data *)f->private_data;
+       char buf[MTIP_DFS_MAX_BUF_SIZE];
+       u32 group_allocated;
+       int size = *offset;
        int n;
 
-       size += sprintf(&buf[size], "Hardware\n--------\n");
-       size += sprintf(&buf[size], "S ACTive      : [ 0x");
+       if (!len || size)
+               return 0;
+
+       if (size < 0)
+               return -EINVAL;
+
+       size += sprintf(&buf[size], "H/ S ACTive      : [ 0x");
 
        for (n = dd->slot_groups-1; n >= 0; n--)
                size += sprintf(&buf[size], "%08X ",
                                         readl(dd->port->s_active[n]));
 
        size += sprintf(&buf[size], "]\n");
-       size += sprintf(&buf[size], "Command Issue : [ 0x");
+       size += sprintf(&buf[size], "H/ Command Issue : [ 0x");
 
        for (n = dd->slot_groups-1; n >= 0; n--)
                size += sprintf(&buf[size], "%08X ",
                                        readl(dd->port->cmd_issue[n]));
 
        size += sprintf(&buf[size], "]\n");
-       size += sprintf(&buf[size], "Completed     : [ 0x");
+       size += sprintf(&buf[size], "H/ Completed     : [ 0x");
 
        for (n = dd->slot_groups-1; n >= 0; n--)
                size += sprintf(&buf[size], "%08X ",
                                readl(dd->port->completed[n]));
 
        size += sprintf(&buf[size], "]\n");
-       size += sprintf(&buf[size], "PORT IRQ STAT : [ 0x%08X ]\n",
+       size += sprintf(&buf[size], "H/ PORT IRQ STAT : [ 0x%08X ]\n",
                                readl(dd->port->mmio + PORT_IRQ_STAT));
-       size += sprintf(&buf[size], "HOST IRQ STAT : [ 0x%08X ]\n",
+       size += sprintf(&buf[size], "H/ HOST IRQ STAT : [ 0x%08X ]\n",
                                readl(dd->mmio + HOST_IRQ_STAT));
        size += sprintf(&buf[size], "\n");
 
-       size += sprintf(&buf[size], "Local\n-----\n");
-       size += sprintf(&buf[size], "Allocated    : [ 0x");
+       size += sprintf(&buf[size], "L/ Allocated     : [ 0x");
 
        for (n = dd->slot_groups-1; n >= 0; n--) {
                if (sizeof(long) > sizeof(u32))
@@ -2605,7 +2630,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
        }
        size += sprintf(&buf[size], "]\n");
 
-       size += sprintf(&buf[size], "Commands in Q: [ 0x");
+       size += sprintf(&buf[size], "L/ Commands in Q : [ 0x");
 
        for (n = dd->slot_groups-1; n >= 0; n--) {
                if (sizeof(long) > sizeof(u32))
@@ -2617,44 +2642,53 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
        }
        size += sprintf(&buf[size], "]\n");
 
-       return size;
+       *offset = size <= len ? size : len;
+       size = copy_to_user(ubuf, buf, *offset);
+       if (size)
+               return -EFAULT;
+
+       return *offset;
 }
 
-static ssize_t mtip_hw_show_status(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
+static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
+                                 size_t len, loff_t *offset)
 {
-       struct driver_data *dd = dev_to_disk(dev)->private_data;
-       int size = 0;
+       struct driver_data *dd =  (struct driver_data *)f->private_data;
+       char buf[MTIP_DFS_MAX_BUF_SIZE];
+       int size = *offset;
 
-       if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
-               size += sprintf(buf, "%s", "thermal_shutdown\n");
-       else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
-               size += sprintf(buf, "%s", "write_protect\n");
-       else
-               size += sprintf(buf, "%s", "online\n");
-
-       return size;
-}
+       if (!len || size)
+               return 0;
 
-static ssize_t mtip_hw_show_flags(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
-{
-       struct driver_data *dd = dev_to_disk(dev)->private_data;
-       int size = 0;
+       if (size < 0)
+               return -EINVAL;
 
-       size += sprintf(&buf[size], "Flag in port struct : [ %08lX ]\n",
+       size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
                                                        dd->port->flags);
-       size += sprintf(&buf[size], "Flag in dd struct   : [ %08lX ]\n",
+       size += sprintf(&buf[size], "Flag-dd   : [ %08lX ]\n",
                                                        dd->dd_flag);
 
-       return size;
+       *offset = size <= len ? size : len;
+       size = copy_to_user(ubuf, buf, *offset);
+       if (size)
+               return -EFAULT;
+
+       return *offset;
 }
 
-static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL);
-static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
-static DEVICE_ATTR(flags, S_IRUGO, mtip_hw_show_flags, NULL);
+static const struct file_operations mtip_regs_fops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .read   = mtip_hw_read_registers,
+       .llseek = no_llseek,
+};
+
+static const struct file_operations mtip_flags_fops = {
+       .owner  = THIS_MODULE,
+       .open   = simple_open,
+       .read   = mtip_hw_read_flags,
+       .llseek = no_llseek,
+};
 
 /*
  * Create the sysfs related attributes.
@@ -2671,15 +2705,9 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
        if (!kobj || !dd)
                return -EINVAL;
 
-       if (sysfs_create_file(kobj, &dev_attr_registers.attr))
-               dev_warn(&dd->pdev->dev,
-                       "Error creating 'registers' sysfs entry\n");
        if (sysfs_create_file(kobj, &dev_attr_status.attr))
                dev_warn(&dd->pdev->dev,
                        "Error creating 'status' sysfs entry\n");
-       if (sysfs_create_file(kobj, &dev_attr_flags.attr))
-               dev_warn(&dd->pdev->dev,
-                       "Error creating 'flags' sysfs entry\n");
        return 0;
 }
 
@@ -2698,13 +2726,39 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
        if (!kobj || !dd)
                return -EINVAL;
 
-       sysfs_remove_file(kobj, &dev_attr_registers.attr);
        sysfs_remove_file(kobj, &dev_attr_status.attr);
-       sysfs_remove_file(kobj, &dev_attr_flags.attr);
 
        return 0;
 }
 
+static int mtip_hw_debugfs_init(struct driver_data *dd)
+{
+       if (!dfs_parent)
+               return -1;
+
+       dd->dfs_node = debugfs_create_dir(dd->disk->disk_name, dfs_parent);
+       if (IS_ERR_OR_NULL(dd->dfs_node)) {
+               dev_warn(&dd->pdev->dev,
+                       "Error creating node %s under debugfs\n",
+                                               dd->disk->disk_name);
+               dd->dfs_node = NULL;
+               return -1;
+       }
+
+       debugfs_create_file("flags", S_IRUGO, dd->dfs_node, dd,
+                                                       &mtip_flags_fops);
+       debugfs_create_file("registers", S_IRUGO, dd->dfs_node, dd,
+                                                       &mtip_regs_fops);
+
+       return 0;
+}
+
+static void mtip_hw_debugfs_exit(struct driver_data *dd)
+{
+       debugfs_remove_recursive(dd->dfs_node);
+}
+
+
 /*
  * Perform any init/resume time hardware setup
  *
@@ -3730,6 +3784,7 @@ skip_create_disk:
                mtip_hw_sysfs_init(dd, kobj);
                kobject_put(kobj);
        }
+       mtip_hw_debugfs_init(dd);
 
        if (dd->mtip_svc_handler) {
                set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
@@ -3755,6 +3810,8 @@ start_service_thread:
        return rv;
 
 kthread_run_error:
+       mtip_hw_debugfs_exit(dd);
+
        /* Delete our gendisk. This also removes the device from /dev */
        del_gendisk(dd->disk);
 
@@ -3805,6 +3862,7 @@ static int mtip_block_remove(struct driver_data *dd)
                        kobject_put(kobj);
                }
        }
+       mtip_hw_debugfs_exit(dd);
 
        /*
         * Delete our gendisk structure. This also removes the device
@@ -4152,10 +4210,20 @@ static int __init mtip_init(void)
        }
        mtip_major = error;
 
+       if (!dfs_parent) {
+               dfs_parent = debugfs_create_dir("rssd", NULL);
+               if (IS_ERR_OR_NULL(dfs_parent)) {
+                       printk(KERN_WARNING "Error creating debugfs parent\n");
+                       dfs_parent = NULL;
+               }
+       }
+
        /* Register our PCI operations. */
        error = pci_register_driver(&mtip_pci_driver);
-       if (error)
+       if (error) {
+               debugfs_remove(dfs_parent);
                unregister_blkdev(mtip_major, MTIP_DRV_NAME);
+       }
 
        return error;
 }
@@ -4172,6 +4240,8 @@ static int __init mtip_init(void)
  */
 static void __exit mtip_exit(void)
 {
+       debugfs_remove_recursive(dfs_parent);
+
        /* Release the allocated major block device number. */
        unregister_blkdev(mtip_major, MTIP_DRV_NAME);
 
index b2c88da26b2a7b7f94ff77b6f1a1d2047f6b45f3..f51fc23d17bb0e0025c74ac9f495007dcbc8b784 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/ata.h>
 #include <linux/interrupt.h>
 #include <linux/genhd.h>
-#include <linux/version.h>
 
 /* Offset of Subsystem Device ID in pci confoguration space */
 #define PCI_SUBSYSTEM_DEVICEID 0x2E
  #define dbg_printk(format, arg...)
 #endif
 
+#define MTIP_DFS_MAX_BUF_SIZE 1024
+
 #define __force_bit2int (unsigned int __force)
 
 enum {
@@ -447,6 +448,8 @@ struct driver_data {
        unsigned long dd_flag; /* NOTE: use atomic bit operations on this */
 
        struct task_struct *mtip_svc_handler; /* task_struct of svc thd */
+
+       struct dentry *dfs_node;
 };
 
 #endif
index 65665c9c42c62ba5805324df96292e560f16b04a..8f428a8ab003d8c7a029036eea6a1666a96d7dd3 100644 (file)
@@ -499,7 +499,7 @@ static int rbd_header_from_disk(struct rbd_image_header *header,
                         / sizeof (*ondisk))
                return -EINVAL;
        header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
-                               snap_count * sizeof (*ondisk),
+                               snap_count * sizeof(u64),
                                gfp_flags);
        if (!header->snapc)
                return -ENOMEM;
@@ -977,7 +977,7 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
        op = (void *)(replyhead + 1);
        rc = le32_to_cpu(replyhead->result);
        bytes = le64_to_cpu(op->extent.length);
-       read_op = (le32_to_cpu(op->op) == CEPH_OSD_OP_READ);
+       read_op = (le16_to_cpu(op->op) == CEPH_OSD_OP_READ);
 
        dout("rbd_req_cb bytes=%lld readop=%d rc=%d\n", bytes, read_op, rc);
 
index aa2712060bfbcd153e446f5adcf80a9d61377e75..9a72277a31df0cb131f879bb8a1503a65a57b7cc 100644 (file)
@@ -513,6 +513,44 @@ static void process_page(unsigned long data)
        }
 }
 
+struct mm_plug_cb {
+       struct blk_plug_cb cb;
+       struct cardinfo *card;
+};
+
+static void mm_unplug(struct blk_plug_cb *cb)
+{
+       struct mm_plug_cb *mmcb = container_of(cb, struct mm_plug_cb, cb);
+
+       spin_lock_irq(&mmcb->card->lock);
+       activate(mmcb->card);
+       spin_unlock_irq(&mmcb->card->lock);
+       kfree(mmcb);
+}
+
+static int mm_check_plugged(struct cardinfo *card)
+{
+       struct blk_plug *plug = current->plug;
+       struct mm_plug_cb *mmcb;
+
+       if (!plug)
+               return 0;
+
+       list_for_each_entry(mmcb, &plug->cb_list, cb.list) {
+               if (mmcb->cb.callback == mm_unplug && mmcb->card == card)
+                       return 1;
+       }
+       /* Not currently on the callback list */
+       mmcb = kmalloc(sizeof(*mmcb), GFP_ATOMIC);
+       if (!mmcb)
+               return 0;
+
+       mmcb->card = card;
+       mmcb->cb.callback = mm_unplug;
+       list_add(&mmcb->cb.list, &plug->cb_list);
+       return 1;
+}
+
 static void mm_make_request(struct request_queue *q, struct bio *bio)
 {
        struct cardinfo *card = q->queuedata;
@@ -523,6 +561,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio)
        *card->biotail = bio;
        bio->bi_next = NULL;
        card->biotail = &bio->bi_next;
+       if (bio->bi_rw & REQ_SYNC || !mm_check_plugged(card))
+               activate(card);
        spin_unlock_irq(&card->lock);
 
        return;
index 773cf27dc23fc595d6fca48ea8ec6c4992438d18..9ad3b5ec1dc1c521085db47a7928cc8cf1179701 100644 (file)
@@ -257,6 +257,7 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
                break;
        case BLKIF_OP_DISCARD:
                dst->u.discard.flag = src->u.discard.flag;
+               dst->u.discard.id = src->u.discard.id;
                dst->u.discard.sector_number = src->u.discard.sector_number;
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
@@ -287,6 +288,7 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
                break;
        case BLKIF_OP_DISCARD:
                dst->u.discard.flag = src->u.discard.flag;
+               dst->u.discard.id = src->u.discard.id;
                dst->u.discard.sector_number = src->u.discard.sector_number;
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
index 60eed4bdd2e4528ae3c3b8871cd65f85d3c34952..e4fb3374dcd2aaa6d0f834cd9394564a3c022a38 100644 (file)
@@ -141,14 +141,36 @@ static int get_id_from_freelist(struct blkfront_info *info)
        return free;
 }
 
-static void add_id_to_freelist(struct blkfront_info *info,
+static int add_id_to_freelist(struct blkfront_info *info,
                               unsigned long id)
 {
+       if (info->shadow[id].req.u.rw.id != id)
+               return -EINVAL;
+       if (info->shadow[id].request == NULL)
+               return -EINVAL;
        info->shadow[id].req.u.rw.id  = info->shadow_free;
        info->shadow[id].request = NULL;
        info->shadow_free = id;
+       return 0;
 }
 
+static const char *op_name(int op)
+{
+       static const char *const names[] = {
+               [BLKIF_OP_READ] = "read",
+               [BLKIF_OP_WRITE] = "write",
+               [BLKIF_OP_WRITE_BARRIER] = "barrier",
+               [BLKIF_OP_FLUSH_DISKCACHE] = "flush",
+               [BLKIF_OP_DISCARD] = "discard" };
+
+       if (op < 0 || op >= ARRAY_SIZE(names))
+               return "unknown";
+
+       if (!names[op])
+               return "reserved";
+
+       return names[op];
+}
 static int xlbd_reserve_minors(unsigned int minor, unsigned int nr)
 {
        unsigned int end = minor + nr;
@@ -746,20 +768,36 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
                bret = RING_GET_RESPONSE(&info->ring, i);
                id   = bret->id;
+               /*
+                * The backend has messed up and given us an id that we would
+                * never have given to it (we stamp it up to BLK_RING_SIZE -
+                * look in get_id_from_freelist.
+                */
+               if (id >= BLK_RING_SIZE) {
+                       WARN(1, "%s: response to %s has incorrect id (%ld)\n",
+                            info->gd->disk_name, op_name(bret->operation), id);
+                       /* We can't safely get the 'struct request' as
+                        * the id is busted. */
+                       continue;
+               }
                req  = info->shadow[id].request;
 
                if (bret->operation != BLKIF_OP_DISCARD)
                        blkif_completion(&info->shadow[id]);
 
-               add_id_to_freelist(info, id);
+               if (add_id_to_freelist(info, id)) {
+                       WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n",
+                            info->gd->disk_name, op_name(bret->operation), id);
+                       continue;
+               }
 
                error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
                switch (bret->operation) {
                case BLKIF_OP_DISCARD:
                        if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
                                struct request_queue *rq = info->rq;
-                               printk(KERN_WARNING "blkfront: %s: discard op failed\n",
-                                          info->gd->disk_name);
+                               printk(KERN_WARNING "blkfront: %s: %s op failed\n",
+                                          info->gd->disk_name, op_name(bret->operation));
                                error = -EOPNOTSUPP;
                                info->feature_discard = 0;
                                info->feature_secdiscard = 0;
@@ -771,18 +809,14 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                case BLKIF_OP_FLUSH_DISKCACHE:
                case BLKIF_OP_WRITE_BARRIER:
                        if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
-                               printk(KERN_WARNING "blkfront: %s: write %s op failed\n",
-                                      info->flush_op == BLKIF_OP_WRITE_BARRIER ?
-                                      "barrier" :  "flush disk cache",
-                                      info->gd->disk_name);
+                               printk(KERN_WARNING "blkfront: %s: %s op failed\n",
+                                      info->gd->disk_name, op_name(bret->operation));
                                error = -EOPNOTSUPP;
                        }
                        if (unlikely(bret->status == BLKIF_RSP_ERROR &&
                                     info->shadow[id].req.u.rw.nr_segments == 0)) {
-                               printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n",
-                                      info->flush_op == BLKIF_OP_WRITE_BARRIER ?
-                                      "barrier" :  "flush disk cache",
-                                      info->gd->disk_name);
+                               printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
+                                      info->gd->disk_name, op_name(bret->operation));
                                error = -EOPNOTSUPP;
                        }
                        if (unlikely(error)) {
index 1412565c01afb213407fea17469ce0037f301610..d706bd0e9e800fd791e198b4b573b64296f3f40e 100644 (file)
@@ -162,22 +162,24 @@ static int __exit omap_rng_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 
-static int omap_rng_suspend(struct platform_device *pdev, pm_message_t message)
+static int omap_rng_suspend(struct device *dev)
 {
        omap_rng_write_reg(RNG_MASK_REG, 0x0);
        return 0;
 }
 
-static int omap_rng_resume(struct platform_device *pdev)
+static int omap_rng_resume(struct device *dev)
 {
        omap_rng_write_reg(RNG_MASK_REG, 0x1);
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume);
+#define        OMAP_RNG_PM     (&omap_rng_pm)
+
 #else
 
-#define        omap_rng_suspend        NULL
-#define        omap_rng_resume         NULL
+#define        OMAP_RNG_PM     NULL
 
 #endif
 
@@ -188,11 +190,10 @@ static struct platform_driver omap_rng_driver = {
        .driver = {
                .name           = "omap_rng",
                .owner          = THIS_MODULE,
+               .pm             = OMAP_RNG_PM,
        },
        .probe          = omap_rng_probe,
        .remove         = __exit_p(omap_rng_remove),
-       .suspend        = omap_rng_suspend,
-       .resume         = omap_rng_resume
 };
 
 static int __init omap_rng_init(void)
index 1e638fff40ea2cb01d99d33745ae5f6526787237..83f85cf7fb1b424afd4dde0b104af0ea21a51f7b 100644 (file)
@@ -2503,18 +2503,6 @@ static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
        cleanup_one_si(info);
 }
 
-#ifdef CONFIG_PM
-static int ipmi_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       return 0;
-}
-
-static int ipmi_pci_resume(struct pci_dev *pdev)
-{
-       return 0;
-}
-#endif
-
 static struct pci_device_id ipmi_pci_devices[] = {
        { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
        { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) },
@@ -2527,10 +2515,6 @@ static struct pci_driver ipmi_pci_driver = {
        .id_table =     ipmi_pci_devices,
        .probe =        ipmi_pci_probe,
        .remove =       __devexit_p(ipmi_pci_remove),
-#ifdef CONFIG_PM
-       .suspend =      ipmi_pci_suspend,
-       .resume =       ipmi_pci_resume,
-#endif
 };
 #endif /* CONFIG_PCI */
 
index 45713f0e7d61adc208511a197691d2560557c489..f87780502b4199712a933103723128054eb5a5ab 100644 (file)
@@ -1459,7 +1459,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int old_camera_power;
 
-static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
+static int sonypi_suspend(struct device *dev)
 {
        old_camera_power = sonypi_device.camera_power;
        sonypi_disable();
@@ -1467,14 +1467,16 @@ static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
        return 0;
 }
 
-static int sonypi_resume(struct platform_device *dev)
+static int sonypi_resume(struct device *dev)
 {
        sonypi_enable(old_camera_power);
        return 0;
 }
+
+static SIMPLE_DEV_PM_OPS(sonypi_pm, sonypi_suspend, sonypi_resume);
+#define SONYPI_PM      (&sonypi_pm)
 #else
-#define sonypi_suspend NULL
-#define sonypi_resume  NULL
+#define SONYPI_PM      NULL
 #endif
 
 static void sonypi_shutdown(struct platform_device *dev)
@@ -1486,12 +1488,11 @@ static struct platform_driver sonypi_driver = {
        .driver         = {
                .name   = "sonypi",
                .owner  = THIS_MODULE,
+               .pm     = SONYPI_PM,
        },
        .probe          = sonypi_probe,
        .remove         = __devexit_p(sonypi_remove),
        .shutdown       = sonypi_shutdown,
-       .suspend        = sonypi_suspend,
-       .resume         = sonypi_resume,
 };
 
 static struct platform_device *sonypi_platform_device;
index ad7c7320dd1ba13f6ef55cf8f06ff88203904d49..ae43ac55fc1e0df2fa92ef573753ff3820ba9d68 100644 (file)
@@ -1274,7 +1274,7 @@ static struct tpm_input_header savestate_header = {
  * We are about to suspend. Save the TPM state
  * so that it can be restored.
  */
-int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
+int tpm_pm_suspend(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
        struct tpm_cmd_t cmd;
index b1c5280ac15946fa453dcba5ac2566416985195d..917f727e674059b7e7daa2fc36a9920a306deef6 100644 (file)
@@ -299,7 +299,7 @@ extern ssize_t tpm_write(struct file *, const char __user *, size_t,
                         loff_t *);
 extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
 extern void tpm_remove_hardware(struct device *);
-extern int tpm_pm_suspend(struct device *, pm_message_t);
+extern int tpm_pm_suspend(struct device *);
 extern int tpm_pm_resume(struct device *);
 extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
                             wait_queue_head_t *);
index c64a1bc65349cc3959c488034fbfd892e7ac04cf..678d57019dc46990d4433afbc1637ff2f9208919 100644 (file)
@@ -168,22 +168,14 @@ static void atml_plat_remove(void)
        }
 }
 
-static int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg)
-{
-       return tpm_pm_suspend(&dev->dev, msg);
-}
+static SIMPLE_DEV_PM_OPS(tpm_atml_pm, tpm_pm_suspend, tpm_pm_resume);
 
-static int tpm_atml_resume(struct platform_device *dev)
-{
-       return tpm_pm_resume(&dev->dev);
-}
 static struct platform_driver atml_drv = {
        .driver = {
                .name = "tpm_atmel",
                .owner          = THIS_MODULE,
+               .pm             = &tpm_atml_pm,
        },
-       .suspend = tpm_atml_suspend,
-       .resume = tpm_atml_resume,
 };
 
 static int __init init_atmel(void)
index 4d2464871ada87cab9b5beacc1ec817ee5a93d31..640c9a427b59b1f788a6541e4d81e88e9f9f9f42 100644 (file)
@@ -274,22 +274,13 @@ static void tpm_nsc_remove(struct device *dev)
        }
 }
 
-static int tpm_nsc_suspend(struct platform_device *dev, pm_message_t msg)
-{
-       return tpm_pm_suspend(&dev->dev, msg);
-}
-
-static int tpm_nsc_resume(struct platform_device *dev)
-{
-       return tpm_pm_resume(&dev->dev);
-}
+static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
 
 static struct platform_driver nsc_drv = {
-       .suspend         = tpm_nsc_suspend,
-       .resume          = tpm_nsc_resume,
        .driver          = {
                .name    = "tpm_nsc",
                .owner   = THIS_MODULE,
+               .pm      = &tpm_nsc_pm,
        },
 };
 
index d2a70cae76df758b8db05b0f53142e427b0f6be3..89682fa8801ea0fafb1f8e9556ca148ab0b4f6f9 100644 (file)
@@ -750,7 +750,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
 
 static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
 {
-       return tpm_pm_suspend(&dev->dev, msg);
+       return tpm_pm_suspend(&dev->dev);
 }
 
 static int tpm_tis_pnp_resume(struct pnp_dev *dev)
@@ -806,27 +806,25 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
                    sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 #endif
-static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
-{
-       return tpm_pm_suspend(&dev->dev, msg);
-}
 
-static int tpm_tis_resume(struct platform_device *dev)
+static int tpm_tis_resume(struct device *dev)
 {
-       struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
+       struct tpm_chip *chip = dev_get_drvdata(dev);
 
        if (chip->vendor.irq)
                tpm_tis_reenable_interrupts(chip);
 
-       return tpm_pm_resume(&dev->dev);
+       return tpm_pm_resume(dev);
 }
+
+static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
+
 static struct platform_driver tis_drv = {
        .driver = {
                .name = "tpm_tis",
                .owner          = THIS_MODULE,
+               .pm             = &tpm_tis_pm,
        },
-       .suspend = tpm_tis_suspend,
-       .resume = tpm_tis_resume,
 };
 
 static struct platform_device *pdev;
index 96014e89f1ac9086fdc1d244655573862d6964b3..3669761d1bac7e683ebc95055e75469e65d5e63d 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_CLKDEV_LOOKUP)     += clkdev.o
 obj-$(CONFIG_COMMON_CLK)       += clk.o clk-fixed-rate.o clk-gate.o \
                                   clk-mux.o clk-divider.o clk-fixed-factor.o
 # SoCs specific
+obj-$(CONFIG_ARCH_NOMADIK)     += clk-nomadik.o
 obj-$(CONFIG_ARCH_MXS)         += mxs/
 obj-$(CONFIG_ARCH_SOCFPGA)     += socfpga/
 obj-$(CONFIG_PLAT_SPEAR)       += spear/
diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c
new file mode 100644 (file)
index 0000000..517a8ff
--- /dev/null
@@ -0,0 +1,47 @@
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+
+/*
+ * The Nomadik clock tree is described in the STN8815A12 DB V4.2
+ * reference manual for the chip, page 94 ff.
+ */
+
+void __init nomadik_clk_init(void)
+{
+       struct clk *clk;
+
+       clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
+       clk_register_clkdev(clk, "apb_pclk", NULL);
+       clk_register_clkdev(clk, NULL, "gpio.0");
+       clk_register_clkdev(clk, NULL, "gpio.1");
+       clk_register_clkdev(clk, NULL, "gpio.2");
+       clk_register_clkdev(clk, NULL, "gpio.3");
+       clk_register_clkdev(clk, NULL, "rng");
+
+       /*
+        * The 2.4 MHz TIMCLK reference clock is active at boot time, this is
+        * actually the MXTALCLK @19.2 MHz divided by 8. This clock is used
+        * by the timers and watchdog. See page 105 ff.
+        */
+       clk = clk_register_fixed_rate(NULL, "TIMCLK", NULL, CLK_IS_ROOT,
+                                     2400000);
+       clk_register_clkdev(clk, NULL, "mtu0");
+       clk_register_clkdev(clk, NULL, "mtu1");
+
+       /*
+        * At boot time, PLL2 is set to generate a set of fixed clocks,
+        * one of them is CLK48, the 48 MHz clock, routed to the UART, MMC/SD
+        * I2C, IrDA, USB and SSP blocks.
+        */
+       clk = clk_register_fixed_rate(NULL, "CLK48", NULL, CLK_IS_ROOT,
+                                     48000000);
+       clk_register_clkdev(clk, NULL, "uart0");
+       clk_register_clkdev(clk, NULL, "uart1");
+       clk_register_clkdev(clk, NULL, "mmci");
+       clk_register_clkdev(clk, NULL, "ssp");
+       clk_register_clkdev(clk, NULL, "nmk-i2c.0");
+       clk_register_clkdev(clk, NULL, "nmk-i2c.1");
+}
index dcbe05616090de6d5a830cc8a5950fb282820eee..9a1eb0cfa95f3f0a00a7334f3b276bf623d88cf6 100644 (file)
@@ -1067,26 +1067,24 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent)
 
        old_parent = clk->parent;
 
-       /* find index of new parent clock using cached parent ptrs */
-       if (clk->parents)
-               for (i = 0; i < clk->num_parents; i++)
-                       if (clk->parents[i] == parent)
-                               break;
-       else
+       if (!clk->parents)
                clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
                                                                GFP_KERNEL);
 
        /*
-        * find index of new parent clock using string name comparison
-        * also try to cache the parent to avoid future calls to __clk_lookup
+        * find index of new parent clock using cached parent ptrs,
+        * or if not yet cached, use string name comparison and cache
+        * them now to avoid future calls to __clk_lookup.
         */
-       if (i == clk->num_parents)
-               for (i = 0; i < clk->num_parents; i++)
-                       if (!strcmp(clk->parent_names[i], parent->name)) {
-                               if (clk->parents)
-                                       clk->parents[i] = __clk_lookup(parent->name);
-                               break;
-                       }
+       for (i = 0; i < clk->num_parents; i++) {
+               if (clk->parents && clk->parents[i] == parent)
+                       break;
+               else if (!strcmp(clk->parent_names[i], parent->name)) {
+                       if (clk->parents)
+                               clk->parents[i] = __clk_lookup(parent->name);
+                       break;
+               }
+       }
 
        if (i == clk->num_parents) {
                pr_debug("%s: clock %s is not a possible parent of clock %s\n",
index 8f05652d53e65c61f8df465798754d148123e8f9..0fcec2aae19cc032dfbfb8475319044420a22501 100644 (file)
@@ -345,31 +345,30 @@ static struct frac_rate_tbl gen_rtbl[] = {
 /* clock parents */
 static const char *vco_parents[] = { "osc_24m_clk", "osc_25m_clk", };
 static const char *gpt_parents[] = { "osc_24m_clk", "apb_clk", };
-static const char *uart0_parents[] = { "pll5_clk", "uart_synth_gate_clk", };
-static const char *c3_parents[] = { "pll5_clk", "c3_synth_gate_clk", };
-static const char *gmac_phy_input_parents[] = { "gmii_125m_pad_clk", "pll2_clk",
+static const char *uart0_parents[] = { "pll5_clk", "uart_syn_gclk", };
+static const char *c3_parents[] = { "pll5_clk", "c3_syn_gclk", };
+static const char *gmac_phy_input_parents[] = { "gmii_pad_clk", "pll2_clk",
        "osc_25m_clk", };
-static const char *gmac_phy_parents[] = { "gmac_phy_input_mux_clk",
-       "gmac_phy_synth_gate_clk", };
+static const char *gmac_phy_parents[] = { "phy_input_mclk", "phy_syn_gclk", };
 static const char *clcd_synth_parents[] = { "vco1div4_clk", "pll2_clk", };
-static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_synth_clk", };
+static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_syn_clk", };
 static const char *i2s_src_parents[] = { "vco1div2_clk", "none", "pll3_clk",
        "i2s_src_pad_clk", };
-static const char *i2s_ref_parents[] = { "i2s_src_mux_clk", "i2s_prs1_clk", };
+static const char *i2s_ref_parents[] = { "i2s_src_mclk", "i2s_prs1_clk", };
 static const char *gen_synth0_1_parents[] = { "vco1div4_clk", "vco3div2_clk",
        "pll3_clk", };
 static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco3div2_clk",
        "pll2_clk", };
 static const char *rmii_phy_parents[] = { "ras_tx50_clk", "none",
-       "ras_pll2_clk", "ras_synth0_clk", };
+       "ras_pll2_clk", "ras_syn0_clk", };
 static const char *smii_rgmii_phy_parents[] = { "none", "ras_tx125_clk",
-       "ras_pll2_clk", "ras_synth0_clk", };
-static const char *uart_parents[] = { "ras_apb_clk", "gen_synth3_clk", };
-static const char *i2c_parents[] = { "ras_apb_clk", "gen_synth1_clk", };
-static const char *ssp1_parents[] = { "ras_apb_clk", "gen_synth1_clk",
+       "ras_pll2_clk", "ras_syn0_clk", };
+static const char *uart_parents[] = { "ras_apb_clk", "gen_syn3_clk", };
+static const char *i2c_parents[] = { "ras_apb_clk", "gen_syn1_clk", };
+static const char *ssp1_parents[] = { "ras_apb_clk", "gen_syn1_clk",
        "ras_plclk0_clk", };
-static const char *pci_parents[] = { "ras_pll3_clk", "gen_synth2_clk", };
-static const char *tdm_parents[] = { "ras_pll3_clk", "gen_synth1_clk", };
+static const char *pci_parents[] = { "ras_pll3_clk", "gen_syn2_clk", };
+static const char *tdm_parents[] = { "ras_pll3_clk", "gen_syn1_clk", };
 
 void __init spear1310_clk_init(void)
 {
@@ -390,9 +389,9 @@ void __init spear1310_clk_init(void)
                        25000000);
        clk_register_clkdev(clk, "osc_25m_clk", NULL);
 
-       clk = clk_register_fixed_rate(NULL, "gmii_125m_pad_clk", NULL,
-                       CLK_IS_ROOT, 125000000);
-       clk_register_clkdev(clk, "gmii_125m_pad_clk", NULL);
+       clk = clk_register_fixed_rate(NULL, "gmii_pad_clk", NULL, CLK_IS_ROOT,
+                       125000000);
+       clk_register_clkdev(clk, "gmii_pad_clk", NULL);
 
        clk = clk_register_fixed_rate(NULL, "i2s_src_pad_clk", NULL,
                        CLK_IS_ROOT, 12288000);
@@ -406,34 +405,34 @@ void __init spear1310_clk_init(void)
 
        /* clock derived from 24 or 25 MHz osc clk */
        /* vco-pll */
-       clk = clk_register_mux(NULL, "vco1_mux_clk", vco_parents,
+       clk = clk_register_mux(NULL, "vco1_mclk", vco_parents,
                        ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
                        SPEAR1310_PLL1_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "vco1_mux_clk", NULL);
-       clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mux_clk",
+       clk_register_clkdev(clk, "vco1_mclk", NULL);
+       clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk",
                        0, SPEAR1310_PLL1_CTR, SPEAR1310_PLL1_FRQ, pll_rtbl,
                        ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL);
        clk_register_clkdev(clk, "vco1_clk", NULL);
        clk_register_clkdev(clk1, "pll1_clk", NULL);
 
-       clk = clk_register_mux(NULL, "vco2_mux_clk", vco_parents,
+       clk = clk_register_mux(NULL, "vco2_mclk", vco_parents,
                        ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
                        SPEAR1310_PLL2_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "vco2_mux_clk", NULL);
-       clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mux_clk",
+       clk_register_clkdev(clk, "vco2_mclk", NULL);
+       clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk",
                        0, SPEAR1310_PLL2_CTR, SPEAR1310_PLL2_FRQ, pll_rtbl,
                        ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL);
        clk_register_clkdev(clk, "vco2_clk", NULL);
        clk_register_clkdev(clk1, "pll2_clk", NULL);
 
-       clk = clk_register_mux(NULL, "vco3_mux_clk", vco_parents,
+       clk = clk_register_mux(NULL, "vco3_mclk", vco_parents,
                        ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
                        SPEAR1310_PLL3_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "vco3_mux_clk", NULL);
-       clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mux_clk",
+       clk_register_clkdev(clk, "vco3_mclk", NULL);
+       clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk",
                        0, SPEAR1310_PLL3_CTR, SPEAR1310_PLL3_FRQ, pll_rtbl,
                        ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL);
        clk_register_clkdev(clk, "vco3_clk", NULL);
@@ -473,7 +472,7 @@ void __init spear1310_clk_init(void)
        /* peripherals */
        clk_register_fixed_factor(NULL, "thermal_clk", "osc_24m_clk", 0, 1,
                        128);
-       clk = clk_register_gate(NULL, "thermal_gate_clk", "thermal_clk", 0,
+       clk = clk_register_gate(NULL, "thermal_gclk", "thermal_clk", 0,
                        SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_THSENS_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_thermal");
@@ -500,177 +499,176 @@ void __init spear1310_clk_init(void)
        clk_register_clkdev(clk, "apb_clk", NULL);
 
        /* gpt clocks */
-       clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
                        SPEAR1310_GPT0_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt0_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt0_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT0_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt0");
 
-       clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
                        SPEAR1310_GPT1_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt1_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt1_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt1");
 
-       clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
                        SPEAR1310_GPT2_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt2_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt2_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
                        SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT2_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt2");
 
-       clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
                        SPEAR1310_GPT3_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt3_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt3_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
                        SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT3_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt3");
 
        /* others */
-       clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk",
-                       "vco1div2_clk", 0, SPEAR1310_UART_CLK_SYNT, NULL,
-                       aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "uart_synth_clk", NULL);
-       clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL);
+       clk = clk_register_aux("uart_syn_clk", "uart_syn_gclk", "vco1div2_clk",
+                       0, SPEAR1310_UART_CLK_SYNT, NULL, aux_rtbl,
+                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
+       clk_register_clkdev(clk, "uart_syn_clk", NULL);
+       clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents,
+       clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
                        ARRAY_SIZE(uart0_parents), 0, SPEAR1310_PERIP_CLK_CFG,
                        SPEAR1310_UART_CLK_SHIFT, SPEAR1310_UART_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "uart0_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart0_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart0_clk", "uart0_mux_clk", 0,
+       clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UART_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "e0000000.serial");
 
-       clk = clk_register_aux("sdhci_synth_clk", "sdhci_synth_gate_clk",
+       clk = clk_register_aux("sdhci_syn_clk", "sdhci_syn_gclk",
                        "vco1div2_clk", 0, SPEAR1310_SDHCI_CLK_SYNT, NULL,
                        aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "sdhci_synth_clk", NULL);
-       clk_register_clkdev(clk1, "sdhci_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "sdhci_syn_clk", NULL);
+       clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL);
 
-       clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_synth_gate_clk", 0,
+       clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SDHCI_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "b3000000.sdhci");
 
-       clk = clk_register_aux("cfxd_synth_clk", "cfxd_synth_gate_clk",
-                       "vco1div2_clk", 0, SPEAR1310_CFXD_CLK_SYNT, NULL,
-                       aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "cfxd_synth_clk", NULL);
-       clk_register_clkdev(clk1, "cfxd_synth_gate_clk", NULL);
+       clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk",
+                       0, SPEAR1310_CFXD_CLK_SYNT, NULL, aux_rtbl,
+                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
+       clk_register_clkdev(clk, "cfxd_syn_clk", NULL);
+       clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL);
 
-       clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_synth_gate_clk", 0,
+       clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CFXD_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "b2800000.cf");
        clk_register_clkdev(clk, NULL, "arasan_xd");
 
-       clk = clk_register_aux("c3_synth_clk", "c3_synth_gate_clk",
-                       "vco1div2_clk", 0, SPEAR1310_C3_CLK_SYNT, NULL,
-                       aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "c3_synth_clk", NULL);
-       clk_register_clkdev(clk1, "c3_synth_gate_clk", NULL);
+       clk = clk_register_aux("c3_syn_clk", "c3_syn_gclk", "vco1div2_clk",
+                       0, SPEAR1310_C3_CLK_SYNT, NULL, aux_rtbl,
+                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
+       clk_register_clkdev(clk, "c3_syn_clk", NULL);
+       clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "c3_mux_clk", c3_parents,
+       clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
                        ARRAY_SIZE(c3_parents), 0, SPEAR1310_PERIP_CLK_CFG,
                        SPEAR1310_C3_CLK_SHIFT, SPEAR1310_C3_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "c3_mux_clk", NULL);
+       clk_register_clkdev(clk, "c3_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "c3_clk", "c3_mux_clk", 0,
+       clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_C3_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "c3");
 
        /* gmac */
-       clk = clk_register_mux(NULL, "gmac_phy_input_mux_clk",
-                       gmac_phy_input_parents,
+       clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
                        ARRAY_SIZE(gmac_phy_input_parents), 0,
                        SPEAR1310_GMAC_CLK_CFG,
                        SPEAR1310_GMAC_PHY_INPUT_CLK_SHIFT,
                        SPEAR1310_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gmac_phy_input_mux_clk", NULL);
+       clk_register_clkdev(clk, "phy_input_mclk", NULL);
 
-       clk = clk_register_aux("gmac_phy_synth_clk", "gmac_phy_synth_gate_clk",
-                       "gmac_phy_input_mux_clk", 0, SPEAR1310_GMAC_CLK_SYNT,
-                       NULL, gmac_rtbl, ARRAY_SIZE(gmac_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "gmac_phy_synth_clk", NULL);
-       clk_register_clkdev(clk1, "gmac_phy_synth_gate_clk", NULL);
+       clk = clk_register_aux("phy_syn_clk", "phy_syn_gclk", "phy_input_mclk",
+                       0, SPEAR1310_GMAC_CLK_SYNT, NULL, gmac_rtbl,
+                       ARRAY_SIZE(gmac_rtbl), &_lock, &clk1);
+       clk_register_clkdev(clk, "phy_syn_clk", NULL);
+       clk_register_clkdev(clk1, "phy_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "gmac_phy_mux_clk", gmac_phy_parents,
+       clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents,
                        ARRAY_SIZE(gmac_phy_parents), 0,
                        SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GMAC_PHY_CLK_SHIFT,
                        SPEAR1310_GMAC_PHY_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "stmmacphy.0");
 
        /* clcd */
-       clk = clk_register_mux(NULL, "clcd_synth_mux_clk", clcd_synth_parents,
+       clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
                        ARRAY_SIZE(clcd_synth_parents), 0,
                        SPEAR1310_CLCD_CLK_SYNT, SPEAR1310_CLCD_SYNT_CLK_SHIFT,
                        SPEAR1310_CLCD_SYNT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "clcd_synth_mux_clk", NULL);
+       clk_register_clkdev(clk, "clcd_syn_mclk", NULL);
 
-       clk = clk_register_frac("clcd_synth_clk", "clcd_synth_mux_clk", 0,
+       clk = clk_register_frac("clcd_syn_clk", "clcd_syn_mclk", 0,
                        SPEAR1310_CLCD_CLK_SYNT, clcd_rtbl,
                        ARRAY_SIZE(clcd_rtbl), &_lock);
-       clk_register_clkdev(clk, "clcd_synth_clk", NULL);
+       clk_register_clkdev(clk, "clcd_syn_clk", NULL);
 
-       clk = clk_register_mux(NULL, "clcd_pixel_mux_clk", clcd_pixel_parents,
+       clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
                        ARRAY_SIZE(clcd_pixel_parents), 0,
                        SPEAR1310_PERIP_CLK_CFG, SPEAR1310_CLCD_CLK_SHIFT,
                        SPEAR1310_CLCD_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "clcd_pixel_clk", NULL);
 
-       clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mux_clk", 0,
+       clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CLCD_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, "clcd_clk", NULL);
 
        /* i2s */
-       clk = clk_register_mux(NULL, "i2s_src_mux_clk", i2s_src_parents,
+       clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
                        ARRAY_SIZE(i2s_src_parents), 0, SPEAR1310_I2S_CLK_CFG,
                        SPEAR1310_I2S_SRC_CLK_SHIFT, SPEAR1310_I2S_SRC_CLK_MASK,
                        0, &_lock);
        clk_register_clkdev(clk, "i2s_src_clk", NULL);
 
-       clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mux_clk", 0,
+       clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
                        SPEAR1310_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl,
                        ARRAY_SIZE(i2s_prs1_rtbl), &_lock, NULL);
        clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
 
-       clk = clk_register_mux(NULL, "i2s_ref_mux_clk", i2s_ref_parents,
+       clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
                        ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1310_I2S_CLK_CFG,
                        SPEAR1310_I2S_REF_SHIFT, SPEAR1310_I2S_REF_SEL_MASK, 0,
                        &_lock);
        clk_register_clkdev(clk, "i2s_ref_clk", NULL);
 
-       clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0,
                        SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_I2S_REF_PAD_CLK_ENB,
                        0, &_lock);
        clk_register_clkdev(clk, "i2s_ref_pad_clk", NULL);
 
-       clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gate_clk",
+       clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gclk",
                        "i2s_ref_pad_clk", 0, SPEAR1310_I2S_CLK_CFG,
                        &i2s_sclk_masks, i2s_sclk_rtbl,
                        ARRAY_SIZE(i2s_sclk_rtbl), &_lock, &clk1);
        clk_register_clkdev(clk, "i2s_sclk_clk", NULL);
-       clk_register_clkdev(clk1, "i2s_sclk_gate_clk", NULL);
+       clk_register_clkdev(clk1, "i2s_sclk_gclk", NULL);
 
        /* clock derived from ahb clk */
        clk = clk_register_gate(NULL, "i2c0_clk", "ahb_clk", 0,
@@ -747,13 +745,13 @@ void __init spear1310_clk_init(void)
                        &_lock);
        clk_register_clkdev(clk, "sysram1_clk", NULL);
 
-       clk = clk_register_aux("adc_synth_clk", "adc_synth_gate_clk", "ahb_clk",
+       clk = clk_register_aux("adc_syn_clk", "adc_syn_gclk", "ahb_clk",
                        0, SPEAR1310_ADC_CLK_SYNT, NULL, adc_rtbl,
                        ARRAY_SIZE(adc_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "adc_synth_clk", NULL);
-       clk_register_clkdev(clk1, "adc_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "adc_syn_clk", NULL);
+       clk_register_clkdev(clk1, "adc_syn_gclk", NULL);
 
-       clk = clk_register_gate(NULL, "adc_clk", "adc_synth_gate_clk", 0,
+       clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_ADC_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "adc_clk");
@@ -790,37 +788,37 @@ void __init spear1310_clk_init(void)
        clk_register_clkdev(clk, NULL, "e0300000.kbd");
 
        /* RAS clks */
-       clk = clk_register_mux(NULL, "gen_synth0_1_mux_clk",
-                       gen_synth0_1_parents, ARRAY_SIZE(gen_synth0_1_parents),
-                       0, SPEAR1310_PLL_CFG, SPEAR1310_RAS_SYNT0_1_CLK_SHIFT,
+       clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents,
+                       ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1310_PLL_CFG,
+                       SPEAR1310_RAS_SYNT0_1_CLK_SHIFT,
                        SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gen_synth0_1_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn0_1_clk", NULL);
 
-       clk = clk_register_mux(NULL, "gen_synth2_3_mux_clk",
-                       gen_synth2_3_parents, ARRAY_SIZE(gen_synth2_3_parents),
-                       0, SPEAR1310_PLL_CFG, SPEAR1310_RAS_SYNT2_3_CLK_SHIFT,
+       clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
+                       ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1310_PLL_CFG,
+                       SPEAR1310_RAS_SYNT2_3_CLK_SHIFT,
                        SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gen_synth2_3_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn2_3_clk", NULL);
 
-       clk = clk_register_frac("gen_synth0_clk", "gen_synth0_1_clk", 0,
+       clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_clk", 0,
                        SPEAR1310_RAS_CLK_SYNT0, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth0_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn0_clk", NULL);
 
-       clk = clk_register_frac("gen_synth1_clk", "gen_synth0_1_clk", 0,
+       clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_clk", 0,
                        SPEAR1310_RAS_CLK_SYNT1, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth1_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn1_clk", NULL);
 
-       clk = clk_register_frac("gen_synth2_clk", "gen_synth2_3_clk", 0,
+       clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_clk", 0,
                        SPEAR1310_RAS_CLK_SYNT2, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth2_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn2_clk", NULL);
 
-       clk = clk_register_frac("gen_synth3_clk", "gen_synth2_3_clk", 0,
+       clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_clk", 0,
                        SPEAR1310_RAS_CLK_SYNT3, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth3_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn3_clk", NULL);
 
        clk = clk_register_gate(NULL, "ras_osc_24m_clk", "osc_24m_clk", 0,
                        SPEAR1310_RAS_CLK_ENB, SPEAR1310_OSC_24M_CLK_ENB, 0,
@@ -847,7 +845,7 @@ void __init spear1310_clk_init(void)
                        &_lock);
        clk_register_clkdev(clk, "ras_pll3_clk", NULL);
 
-       clk = clk_register_gate(NULL, "ras_tx125_clk", "gmii_125m_pad_clk", 0,
+       clk = clk_register_gate(NULL, "ras_tx125_clk", "gmii_pad_clk", 0,
                        SPEAR1310_RAS_CLK_ENB, SPEAR1310_C125M_PAD_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, "ras_tx125_clk", NULL);
@@ -912,7 +910,7 @@ void __init spear1310_clk_init(void)
                        &_lock);
        clk_register_clkdev(clk, NULL, "5c700000.eth");
 
-       clk = clk_register_mux(NULL, "smii_rgmii_phy_mux_clk",
+       clk = clk_register_mux(NULL, "smii_rgmii_phy_mclk",
                        smii_rgmii_phy_parents,
                        ARRAY_SIZE(smii_rgmii_phy_parents), 0,
                        SPEAR1310_RAS_CTRL_REG1,
@@ -922,184 +920,184 @@ void __init spear1310_clk_init(void)
        clk_register_clkdev(clk, NULL, "stmmacphy.2");
        clk_register_clkdev(clk, NULL, "stmmacphy.4");
 
-       clk = clk_register_mux(NULL, "rmii_phy_mux_clk", rmii_phy_parents,
+       clk = clk_register_mux(NULL, "rmii_phy_mclk", rmii_phy_parents,
                        ARRAY_SIZE(rmii_phy_parents), 0,
                        SPEAR1310_RAS_CTRL_REG1, SPEAR1310_RMII_PHY_CLK_SHIFT,
                        SPEAR1310_PHY_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "stmmacphy.3");
 
-       clk = clk_register_mux(NULL, "uart1_mux_clk", uart_parents,
+       clk = clk_register_mux(NULL, "uart1_mclk", uart_parents,
                        ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_UART1_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
                        0, &_lock);
-       clk_register_clkdev(clk, "uart1_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart1_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart1_clk", "uart1_mux_clk", 0,
+       clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5c800000.serial");
 
-       clk = clk_register_mux(NULL, "uart2_mux_clk", uart_parents,
+       clk = clk_register_mux(NULL, "uart2_mclk", uart_parents,
                        ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_UART2_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
                        0, &_lock);
-       clk_register_clkdev(clk, "uart2_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart2_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart2_clk", "uart2_mux_clk", 0,
+       clk = clk_register_gate(NULL, "uart2_clk", "uart2_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART2_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5c900000.serial");
 
-       clk = clk_register_mux(NULL, "uart3_mux_clk", uart_parents,
+       clk = clk_register_mux(NULL, "uart3_mclk", uart_parents,
                        ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_UART3_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
                        0, &_lock);
-       clk_register_clkdev(clk, "uart3_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart3_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart3_clk", "uart3_mux_clk", 0,
+       clk = clk_register_gate(NULL, "uart3_clk", "uart3_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART3_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5ca00000.serial");
 
-       clk = clk_register_mux(NULL, "uart4_mux_clk", uart_parents,
+       clk = clk_register_mux(NULL, "uart4_mclk", uart_parents,
                        ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_UART4_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
                        0, &_lock);
-       clk_register_clkdev(clk, "uart4_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart4_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart4_clk", "uart4_mux_clk", 0,
+       clk = clk_register_gate(NULL, "uart4_clk", "uart4_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART4_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5cb00000.serial");
 
-       clk = clk_register_mux(NULL, "uart5_mux_clk", uart_parents,
+       clk = clk_register_mux(NULL, "uart5_mclk", uart_parents,
                        ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_UART5_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
                        0, &_lock);
-       clk_register_clkdev(clk, "uart5_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart5_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart5_clk", "uart5_mux_clk", 0,
+       clk = clk_register_gate(NULL, "uart5_clk", "uart5_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_UART5_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5cc00000.serial");
 
-       clk = clk_register_mux(NULL, "i2c1_mux_clk", i2c_parents,
+       clk = clk_register_mux(NULL, "i2c1_mclk", i2c_parents,
                        ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_I2C1_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "i2c1_mux_clk", NULL);
+       clk_register_clkdev(clk, "i2c1_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "i2c1_clk", "i2c1_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2c1_clk", "i2c1_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5cd00000.i2c");
 
-       clk = clk_register_mux(NULL, "i2c2_mux_clk", i2c_parents,
+       clk = clk_register_mux(NULL, "i2c2_mclk", i2c_parents,
                        ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_I2C2_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "i2c2_mux_clk", NULL);
+       clk_register_clkdev(clk, "i2c2_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "i2c2_clk", "i2c2_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2c2_clk", "i2c2_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C2_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5ce00000.i2c");
 
-       clk = clk_register_mux(NULL, "i2c3_mux_clk", i2c_parents,
+       clk = clk_register_mux(NULL, "i2c3_mclk", i2c_parents,
                        ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_I2C3_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "i2c3_mux_clk", NULL);
+       clk_register_clkdev(clk, "i2c3_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "i2c3_clk", "i2c3_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2c3_clk", "i2c3_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C3_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5cf00000.i2c");
 
-       clk = clk_register_mux(NULL, "i2c4_mux_clk", i2c_parents,
+       clk = clk_register_mux(NULL, "i2c4_mclk", i2c_parents,
                        ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_I2C4_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "i2c4_mux_clk", NULL);
+       clk_register_clkdev(clk, "i2c4_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "i2c4_clk", "i2c4_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2c4_clk", "i2c4_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C4_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5d000000.i2c");
 
-       clk = clk_register_mux(NULL, "i2c5_mux_clk", i2c_parents,
+       clk = clk_register_mux(NULL, "i2c5_mclk", i2c_parents,
                        ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_I2C5_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "i2c5_mux_clk", NULL);
+       clk_register_clkdev(clk, "i2c5_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "i2c5_clk", "i2c5_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2c5_clk", "i2c5_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C5_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5d100000.i2c");
 
-       clk = clk_register_mux(NULL, "i2c6_mux_clk", i2c_parents,
+       clk = clk_register_mux(NULL, "i2c6_mclk", i2c_parents,
                        ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_I2C6_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "i2c6_mux_clk", NULL);
+       clk_register_clkdev(clk, "i2c6_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "i2c6_clk", "i2c6_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2c6_clk", "i2c6_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C6_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5d200000.i2c");
 
-       clk = clk_register_mux(NULL, "i2c7_mux_clk", i2c_parents,
+       clk = clk_register_mux(NULL, "i2c7_mclk", i2c_parents,
                        ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_I2C7_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "i2c7_mux_clk", NULL);
+       clk_register_clkdev(clk, "i2c7_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "i2c7_clk", "i2c7_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2c7_clk", "i2c7_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_I2C7_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5d300000.i2c");
 
-       clk = clk_register_mux(NULL, "ssp1_mux_clk", ssp1_parents,
+       clk = clk_register_mux(NULL, "ssp1_mclk", ssp1_parents,
                        ARRAY_SIZE(ssp1_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_SSP1_CLK_SHIFT, SPEAR1310_SSP1_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "ssp1_mux_clk", NULL);
+       clk_register_clkdev(clk, "ssp1_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "ssp1_clk", "ssp1_mux_clk", 0,
+       clk = clk_register_gate(NULL, "ssp1_clk", "ssp1_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_SSP1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "5d400000.spi");
 
-       clk = clk_register_mux(NULL, "pci_mux_clk", pci_parents,
+       clk = clk_register_mux(NULL, "pci_mclk", pci_parents,
                        ARRAY_SIZE(pci_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_PCI_CLK_SHIFT, SPEAR1310_PCI_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "pci_mux_clk", NULL);
+       clk_register_clkdev(clk, "pci_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "pci_clk", "pci_mux_clk", 0,
+       clk = clk_register_gate(NULL, "pci_clk", "pci_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_PCI_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "pci");
 
-       clk = clk_register_mux(NULL, "tdm1_mux_clk", tdm_parents,
+       clk = clk_register_mux(NULL, "tdm1_mclk", tdm_parents,
                        ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_TDM1_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "tdm1_mux_clk", NULL);
+       clk_register_clkdev(clk, "tdm1_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "tdm1_clk", "tdm1_mux_clk", 0,
+       clk = clk_register_gate(NULL, "tdm1_clk", "tdm1_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_TDM1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "tdm_hdlc.0");
 
-       clk = clk_register_mux(NULL, "tdm2_mux_clk", tdm_parents,
+       clk = clk_register_mux(NULL, "tdm2_mclk", tdm_parents,
                        ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0,
                        SPEAR1310_TDM2_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "tdm2_mux_clk", NULL);
+       clk_register_clkdev(clk, "tdm2_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "tdm2_clk", "tdm2_mux_clk", 0,
+       clk = clk_register_gate(NULL, "tdm2_clk", "tdm2_mclk", 0,
                        SPEAR1310_RAS_SW_CLK_CTRL, SPEAR1310_TDM2_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "tdm_hdlc.1");
index e3ea72162236fb6b69db25d3ca9d3bc4cd754367..2352cee7f6455ed95c8b22e6d91824bad15fd1e4 100644 (file)
@@ -369,27 +369,25 @@ static struct frac_rate_tbl gen_rtbl[] = {
 
 /* clock parents */
 static const char *vco_parents[] = { "osc_24m_clk", "osc_25m_clk", };
-static const char *sys_parents[] = { "none", "pll1_clk", "none", "none",
-       "sys_synth_clk", "none", "pll2_clk", "pll3_clk", };
-static const char *ahb_parents[] = { "cpu_div3_clk", "amba_synth_clk", };
+static const char *sys_parents[] = { "pll1_clk", "pll1_clk", "pll1_clk",
+       "pll1_clk", "sys_synth_clk", "sys_synth_clk", "pll2_clk", "pll3_clk", };
+static const char *ahb_parents[] = { "cpu_div3_clk", "amba_syn_clk", };
 static const char *gpt_parents[] = { "osc_24m_clk", "apb_clk", };
 static const char *uart0_parents[] = { "pll5_clk", "osc_24m_clk",
-       "uart0_synth_gate_clk", };
+       "uart0_syn_gclk", };
 static const char *uart1_parents[] = { "pll5_clk", "osc_24m_clk",
-       "uart1_synth_gate_clk", };
-static const char *c3_parents[] = { "pll5_clk", "c3_synth_gate_clk", };
-static const char *gmac_phy_input_parents[] = { "gmii_125m_pad_clk", "pll2_clk",
+       "uart1_syn_gclk", };
+static const char *c3_parents[] = { "pll5_clk", "c3_syn_gclk", };
+static const char *gmac_phy_input_parents[] = { "gmii_pad_clk", "pll2_clk",
        "osc_25m_clk", };
-static const char *gmac_phy_parents[] = { "gmac_phy_input_mux_clk",
-       "gmac_phy_synth_gate_clk", };
+static const char *gmac_phy_parents[] = { "phy_input_mclk", "phy_syn_gclk", };
 static const char *clcd_synth_parents[] = { "vco1div4_clk", "pll2_clk", };
-static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_synth_clk", };
+static const char *clcd_pixel_parents[] = { "pll5_clk", "clcd_syn_clk", };
 static const char *i2s_src_parents[] = { "vco1div2_clk", "pll2_clk", "pll3_clk",
        "i2s_src_pad_clk", };
-static const char *i2s_ref_parents[] = { "i2s_src_mux_clk", "i2s_prs1_clk", };
-static const char *spdif_out_parents[] = { "i2s_src_pad_clk", "gen_synth2_clk",
-};
-static const char *spdif_in_parents[] = { "pll2_clk", "gen_synth3_clk", };
+static const char *i2s_ref_parents[] = { "i2s_src_mclk", "i2s_prs1_clk", };
+static const char *spdif_out_parents[] = { "i2s_src_pad_clk", "gen_syn2_clk", };
+static const char *spdif_in_parents[] = { "pll2_clk", "gen_syn3_clk", };
 
 static const char *gen_synth0_1_parents[] = { "vco1div4_clk", "vco3div2_clk",
        "pll3_clk", };
@@ -415,9 +413,9 @@ void __init spear1340_clk_init(void)
                        25000000);
        clk_register_clkdev(clk, "osc_25m_clk", NULL);
 
-       clk = clk_register_fixed_rate(NULL, "gmii_125m_pad_clk", NULL,
-                       CLK_IS_ROOT, 125000000);
-       clk_register_clkdev(clk, "gmii_125m_pad_clk", NULL);
+       clk = clk_register_fixed_rate(NULL, "gmii_pad_clk", NULL, CLK_IS_ROOT,
+                       125000000);
+       clk_register_clkdev(clk, "gmii_pad_clk", NULL);
 
        clk = clk_register_fixed_rate(NULL, "i2s_src_pad_clk", NULL,
                        CLK_IS_ROOT, 12288000);
@@ -431,35 +429,35 @@ void __init spear1340_clk_init(void)
 
        /* clock derived from 24 or 25 MHz osc clk */
        /* vco-pll */
-       clk = clk_register_mux(NULL, "vco1_mux_clk", vco_parents,
+       clk = clk_register_mux(NULL, "vco1_mclk", vco_parents,
                        ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
                        SPEAR1340_PLL1_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "vco1_mux_clk", NULL);
-       clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mux_clk",
-                       0, SPEAR1340_PLL1_CTR, SPEAR1340_PLL1_FRQ, pll_rtbl,
+       clk_register_clkdev(clk, "vco1_mclk", NULL);
+       clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk", 0,
+                       SPEAR1340_PLL1_CTR, SPEAR1340_PLL1_FRQ, pll_rtbl,
                        ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL);
        clk_register_clkdev(clk, "vco1_clk", NULL);
        clk_register_clkdev(clk1, "pll1_clk", NULL);
 
-       clk = clk_register_mux(NULL, "vco2_mux_clk", vco_parents,
+       clk = clk_register_mux(NULL, "vco2_mclk", vco_parents,
                        ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
                        SPEAR1340_PLL2_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "vco2_mux_clk", NULL);
-       clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mux_clk",
-                       0, SPEAR1340_PLL2_CTR, SPEAR1340_PLL2_FRQ, pll_rtbl,
+       clk_register_clkdev(clk, "vco2_mclk", NULL);
+       clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk", 0,
+                       SPEAR1340_PLL2_CTR, SPEAR1340_PLL2_FRQ, pll_rtbl,
                        ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL);
        clk_register_clkdev(clk, "vco2_clk", NULL);
        clk_register_clkdev(clk1, "pll2_clk", NULL);
 
-       clk = clk_register_mux(NULL, "vco3_mux_clk", vco_parents,
+       clk = clk_register_mux(NULL, "vco3_mclk", vco_parents,
                        ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
                        SPEAR1340_PLL3_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "vco3_mux_clk", NULL);
-       clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mux_clk",
-                       0, SPEAR1340_PLL3_CTR, SPEAR1340_PLL3_FRQ, pll_rtbl,
+       clk_register_clkdev(clk, "vco3_mclk", NULL);
+       clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk", 0,
+                       SPEAR1340_PLL3_CTR, SPEAR1340_PLL3_FRQ, pll_rtbl,
                        ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL);
        clk_register_clkdev(clk, "vco3_clk", NULL);
        clk_register_clkdev(clk1, "pll3_clk", NULL);
@@ -498,7 +496,7 @@ void __init spear1340_clk_init(void)
        /* peripherals */
        clk_register_fixed_factor(NULL, "thermal_clk", "osc_24m_clk", 0, 1,
                        128);
-       clk = clk_register_gate(NULL, "thermal_gate_clk", "thermal_clk", 0,
+       clk = clk_register_gate(NULL, "thermal_gclk", "thermal_clk", 0,
                        SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_THSENS_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_thermal");
@@ -509,23 +507,23 @@ void __init spear1340_clk_init(void)
        clk_register_clkdev(clk, "ddr_clk", NULL);
 
        /* clock derived from pll1 clk */
-       clk = clk_register_frac("sys_synth_clk", "vco1div2_clk", 0,
+       clk = clk_register_frac("sys_syn_clk", "vco1div2_clk", 0,
                        SPEAR1340_SYS_CLK_SYNT, sys_synth_rtbl,
                        ARRAY_SIZE(sys_synth_rtbl), &_lock);
-       clk_register_clkdev(clk, "sys_synth_clk", NULL);
+       clk_register_clkdev(clk, "sys_syn_clk", NULL);
 
-       clk = clk_register_frac("amba_synth_clk", "vco1div2_clk", 0,
+       clk = clk_register_frac("amba_syn_clk", "vco1div2_clk", 0,
                        SPEAR1340_AMBA_CLK_SYNT, amba_synth_rtbl,
                        ARRAY_SIZE(amba_synth_rtbl), &_lock);
-       clk_register_clkdev(clk, "amba_synth_clk", NULL);
+       clk_register_clkdev(clk, "amba_syn_clk", NULL);
 
-       clk = clk_register_mux(NULL, "sys_mux_clk", sys_parents,
+       clk = clk_register_mux(NULL, "sys_mclk", sys_parents,
                        ARRAY_SIZE(sys_parents), 0, SPEAR1340_SYS_CLK_CTRL,
                        SPEAR1340_SCLK_SRC_SEL_SHIFT,
                        SPEAR1340_SCLK_SRC_SEL_MASK, 0, &_lock);
        clk_register_clkdev(clk, "sys_clk", NULL);
 
-       clk = clk_register_fixed_factor(NULL, "cpu_clk", "sys_mux_clk", 0, 1,
+       clk = clk_register_fixed_factor(NULL, "cpu_clk", "sys_mclk", 0, 1,
                        2);
        clk_register_clkdev(clk, "cpu_clk", NULL);
 
@@ -548,194 +546,193 @@ void __init spear1340_clk_init(void)
        clk_register_clkdev(clk, "apb_clk", NULL);
 
        /* gpt clocks */
-       clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
                        SPEAR1340_GPT0_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt0_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt0_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT0_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt0");
 
-       clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
                        SPEAR1340_GPT1_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt1_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt1_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt1");
 
-       clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
                        SPEAR1340_GPT2_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt2_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt2_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
                        SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT2_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt2");
 
-       clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt_parents,
+       clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents,
                        ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
                        SPEAR1340_GPT3_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gpt3_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt3_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
                        SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT3_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "gpt3");
 
        /* others */
-       clk = clk_register_aux("uart0_synth_clk", "uart0_synth_gate_clk",
+       clk = clk_register_aux("uart0_syn_clk", "uart0_syn_gclk",
                        "vco1div2_clk", 0, SPEAR1340_UART0_CLK_SYNT, NULL,
                        aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "uart0_synth_clk", NULL);
-       clk_register_clkdev(clk1, "uart0_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "uart0_syn_clk", NULL);
+       clk_register_clkdev(clk1, "uart0_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents,
+       clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
                        ARRAY_SIZE(uart0_parents), 0, SPEAR1340_PERIP_CLK_CFG,
                        SPEAR1340_UART0_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "uart0_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart0_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart0_clk", "uart0_mux_clk", 0,
+       clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UART0_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "e0000000.serial");
 
-       clk = clk_register_aux("uart1_synth_clk", "uart1_synth_gate_clk",
+       clk = clk_register_aux("uart1_syn_clk", "uart1_syn_gclk",
                        "vco1div2_clk", 0, SPEAR1340_UART1_CLK_SYNT, NULL,
                        aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "uart1_synth_clk", NULL);
-       clk_register_clkdev(clk1, "uart1_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "uart1_syn_clk", NULL);
+       clk_register_clkdev(clk1, "uart1_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "uart1_mux_clk", uart1_parents,
+       clk = clk_register_mux(NULL, "uart1_mclk", uart1_parents,
                        ARRAY_SIZE(uart1_parents), 0, SPEAR1340_PERIP_CLK_CFG,
                        SPEAR1340_UART1_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "uart1_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart1_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart1_clk", "uart1_mux_clk", 0,
-                       SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UART1_CLK_ENB, 0,
+       clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0,
+                       SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_UART1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "b4100000.serial");
 
-       clk = clk_register_aux("sdhci_synth_clk", "sdhci_synth_gate_clk",
+       clk = clk_register_aux("sdhci_syn_clk", "sdhci_syn_gclk",
                        "vco1div2_clk", 0, SPEAR1340_SDHCI_CLK_SYNT, NULL,
                        aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "sdhci_synth_clk", NULL);
-       clk_register_clkdev(clk1, "sdhci_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "sdhci_syn_clk", NULL);
+       clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL);
 
-       clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_synth_gate_clk", 0,
+       clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SDHCI_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "b3000000.sdhci");
 
-       clk = clk_register_aux("cfxd_synth_clk", "cfxd_synth_gate_clk",
-                       "vco1div2_clk", 0, SPEAR1340_CFXD_CLK_SYNT, NULL,
-                       aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "cfxd_synth_clk", NULL);
-       clk_register_clkdev(clk1, "cfxd_synth_gate_clk", NULL);
+       clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk",
+                       0, SPEAR1340_CFXD_CLK_SYNT, NULL, aux_rtbl,
+                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
+       clk_register_clkdev(clk, "cfxd_syn_clk", NULL);
+       clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL);
 
-       clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_synth_gate_clk", 0,
+       clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CFXD_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "b2800000.cf");
        clk_register_clkdev(clk, NULL, "arasan_xd");
 
-       clk = clk_register_aux("c3_synth_clk", "c3_synth_gate_clk",
-                       "vco1div2_clk", 0, SPEAR1340_C3_CLK_SYNT, NULL,
-                       aux_rtbl, ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "c3_synth_clk", NULL);
-       clk_register_clkdev(clk1, "c3_synth_gate_clk", NULL);
+       clk = clk_register_aux("c3_syn_clk", "c3_syn_gclk", "vco1div2_clk", 0,
+                       SPEAR1340_C3_CLK_SYNT, NULL, aux_rtbl,
+                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
+       clk_register_clkdev(clk, "c3_syn_clk", NULL);
+       clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "c3_mux_clk", c3_parents,
+       clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
                        ARRAY_SIZE(c3_parents), 0, SPEAR1340_PERIP_CLK_CFG,
                        SPEAR1340_C3_CLK_SHIFT, SPEAR1340_C3_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "c3_mux_clk", NULL);
+       clk_register_clkdev(clk, "c3_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "c3_clk", "c3_mux_clk", 0,
+       clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_C3_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "c3");
 
        /* gmac */
-       clk = clk_register_mux(NULL, "gmac_phy_input_mux_clk",
-                       gmac_phy_input_parents,
+       clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
                        ARRAY_SIZE(gmac_phy_input_parents), 0,
                        SPEAR1340_GMAC_CLK_CFG,
                        SPEAR1340_GMAC_PHY_INPUT_CLK_SHIFT,
                        SPEAR1340_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gmac_phy_input_mux_clk", NULL);
+       clk_register_clkdev(clk, "phy_input_mclk", NULL);
 
-       clk = clk_register_aux("gmac_phy_synth_clk", "gmac_phy_synth_gate_clk",
-                       "gmac_phy_input_mux_clk", 0, SPEAR1340_GMAC_CLK_SYNT,
-                       NULL, gmac_rtbl, ARRAY_SIZE(gmac_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "gmac_phy_synth_clk", NULL);
-       clk_register_clkdev(clk1, "gmac_phy_synth_gate_clk", NULL);
+       clk = clk_register_aux("phy_syn_clk", "phy_syn_gclk", "phy_input_mclk",
+                       0, SPEAR1340_GMAC_CLK_SYNT, NULL, gmac_rtbl,
+                       ARRAY_SIZE(gmac_rtbl), &_lock, &clk1);
+       clk_register_clkdev(clk, "phy_syn_clk", NULL);
+       clk_register_clkdev(clk1, "phy_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "gmac_phy_mux_clk", gmac_phy_parents,
+       clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents,
                        ARRAY_SIZE(gmac_phy_parents), 0,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GMAC_PHY_CLK_SHIFT,
                        SPEAR1340_GMAC_PHY_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "stmmacphy.0");
 
        /* clcd */
-       clk = clk_register_mux(NULL, "clcd_synth_mux_clk", clcd_synth_parents,
+       clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
                        ARRAY_SIZE(clcd_synth_parents), 0,
                        SPEAR1340_CLCD_CLK_SYNT, SPEAR1340_CLCD_SYNT_CLK_SHIFT,
                        SPEAR1340_CLCD_SYNT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "clcd_synth_mux_clk", NULL);
+       clk_register_clkdev(clk, "clcd_syn_mclk", NULL);
 
-       clk = clk_register_frac("clcd_synth_clk", "clcd_synth_mux_clk", 0,
+       clk = clk_register_frac("clcd_syn_clk", "clcd_syn_mclk", 0,
                        SPEAR1340_CLCD_CLK_SYNT, clcd_rtbl,
                        ARRAY_SIZE(clcd_rtbl), &_lock);
-       clk_register_clkdev(clk, "clcd_synth_clk", NULL);
+       clk_register_clkdev(clk, "clcd_syn_clk", NULL);
 
-       clk = clk_register_mux(NULL, "clcd_pixel_mux_clk", clcd_pixel_parents,
+       clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
                        ARRAY_SIZE(clcd_pixel_parents), 0,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_CLCD_CLK_SHIFT,
                        SPEAR1340_CLCD_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "clcd_pixel_clk", NULL);
 
-       clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mux_clk", 0,
+       clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CLCD_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, "clcd_clk", NULL);
 
        /* i2s */
-       clk = clk_register_mux(NULL, "i2s_src_mux_clk", i2s_src_parents,
+       clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
                        ARRAY_SIZE(i2s_src_parents), 0, SPEAR1340_I2S_CLK_CFG,
                        SPEAR1340_I2S_SRC_CLK_SHIFT, SPEAR1340_I2S_SRC_CLK_MASK,
                        0, &_lock);
        clk_register_clkdev(clk, "i2s_src_clk", NULL);
 
-       clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mux_clk", 0,
+       clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
                        SPEAR1340_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl,
                        ARRAY_SIZE(i2s_prs1_rtbl), &_lock, NULL);
        clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
 
-       clk = clk_register_mux(NULL, "i2s_ref_mux_clk", i2s_ref_parents,
+       clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
                        ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1340_I2S_CLK_CFG,
                        SPEAR1340_I2S_REF_SHIFT, SPEAR1340_I2S_REF_SEL_MASK, 0,
                        &_lock);
        clk_register_clkdev(clk, "i2s_ref_clk", NULL);
 
-       clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mux_clk", 0,
+       clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0,
                        SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_I2S_REF_PAD_CLK_ENB,
                        0, &_lock);
        clk_register_clkdev(clk, "i2s_ref_pad_clk", NULL);
 
-       clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gate_clk",
-                       "i2s_ref_mux_clk", 0, SPEAR1340_I2S_CLK_CFG,
-                       &i2s_sclk_masks, i2s_sclk_rtbl,
-                       ARRAY_SIZE(i2s_sclk_rtbl), &_lock, &clk1);
+       clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gclk", "i2s_ref_mclk",
+                       0, SPEAR1340_I2S_CLK_CFG, &i2s_sclk_masks,
+                       i2s_sclk_rtbl, ARRAY_SIZE(i2s_sclk_rtbl), &_lock,
+                       &clk1);
        clk_register_clkdev(clk, "i2s_sclk_clk", NULL);
-       clk_register_clkdev(clk1, "i2s_sclk_gate_clk", NULL);
+       clk_register_clkdev(clk1, "i2s_sclk_gclk", NULL);
 
        /* clock derived from ahb clk */
        clk = clk_register_gate(NULL, "i2c0_clk", "ahb_clk", 0,
@@ -744,7 +741,7 @@ void __init spear1340_clk_init(void)
        clk_register_clkdev(clk, NULL, "e0280000.i2c");
 
        clk = clk_register_gate(NULL, "i2c1_clk", "ahb_clk", 0,
-                       SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2C1_CLK_ENB, 0,
+                       SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_I2C1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "b4000000.i2c");
 
@@ -800,13 +797,13 @@ void __init spear1340_clk_init(void)
                        &_lock);
        clk_register_clkdev(clk, "sysram1_clk", NULL);
 
-       clk = clk_register_aux("adc_synth_clk", "adc_synth_gate_clk", "ahb_clk",
+       clk = clk_register_aux("adc_syn_clk", "adc_syn_gclk", "ahb_clk",
                        0, SPEAR1340_ADC_CLK_SYNT, NULL, adc_rtbl,
                        ARRAY_SIZE(adc_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "adc_synth_clk", NULL);
-       clk_register_clkdev(clk1, "adc_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "adc_syn_clk", NULL);
+       clk_register_clkdev(clk1, "adc_syn_gclk", NULL);
 
-       clk = clk_register_gate(NULL, "adc_clk", "adc_synth_gate_clk", 0,
+       clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_ADC_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "adc_clk");
@@ -843,39 +840,39 @@ void __init spear1340_clk_init(void)
        clk_register_clkdev(clk, NULL, "e0300000.kbd");
 
        /* RAS clks */
-       clk = clk_register_mux(NULL, "gen_synth0_1_mux_clk",
-                       gen_synth0_1_parents, ARRAY_SIZE(gen_synth0_1_parents),
-                       0, SPEAR1340_PLL_CFG, SPEAR1340_GEN_SYNT0_1_CLK_SHIFT,
+       clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents,
+                       ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1340_PLL_CFG,
+                       SPEAR1340_GEN_SYNT0_1_CLK_SHIFT,
                        SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gen_synth0_1_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn0_1_clk", NULL);
 
-       clk = clk_register_mux(NULL, "gen_synth2_3_mux_clk",
-                       gen_synth2_3_parents, ARRAY_SIZE(gen_synth2_3_parents),
-                       0, SPEAR1340_PLL_CFG, SPEAR1340_GEN_SYNT2_3_CLK_SHIFT,
+       clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
+                       ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1340_PLL_CFG,
+                       SPEAR1340_GEN_SYNT2_3_CLK_SHIFT,
                        SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gen_synth2_3_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn2_3_clk", NULL);
 
-       clk = clk_register_frac("gen_synth0_clk", "gen_synth0_1_clk", 0,
+       clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_clk", 0,
                        SPEAR1340_GEN_CLK_SYNT0, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth0_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn0_clk", NULL);
 
-       clk = clk_register_frac("gen_synth1_clk", "gen_synth0_1_clk", 0,
+       clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_clk", 0,
                        SPEAR1340_GEN_CLK_SYNT1, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth1_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn1_clk", NULL);
 
-       clk = clk_register_frac("gen_synth2_clk", "gen_synth2_3_clk", 0,
+       clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_clk", 0,
                        SPEAR1340_GEN_CLK_SYNT2, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth2_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn2_clk", NULL);
 
-       clk = clk_register_frac("gen_synth3_clk", "gen_synth2_3_clk", 0,
+       clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_clk", 0,
                        SPEAR1340_GEN_CLK_SYNT3, gen_rtbl, ARRAY_SIZE(gen_rtbl),
                        &_lock);
-       clk_register_clkdev(clk, "gen_synth3_clk", NULL);
+       clk_register_clkdev(clk, "gen_syn3_clk", NULL);
 
-       clk = clk_register_gate(NULL, "mali_clk", "gen_synth3_clk", 0,
+       clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_MALI_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "mali");
@@ -890,74 +887,74 @@ void __init spear1340_clk_init(void)
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_cec.1");
 
-       clk = clk_register_mux(NULL, "spdif_out_mux_clk", spdif_out_parents,
+       clk = clk_register_mux(NULL, "spdif_out_mclk", spdif_out_parents,
                        ARRAY_SIZE(spdif_out_parents), 0,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_OUT_CLK_SHIFT,
                        SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "spdif_out_mux_clk", NULL);
+       clk_register_clkdev(clk, "spdif_out_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mux_clk", 0,
+       clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_OUT_CLK_ENB,
                        0, &_lock);
        clk_register_clkdev(clk, NULL, "spdif-out");
 
-       clk = clk_register_mux(NULL, "spdif_in_mux_clk", spdif_in_parents,
+       clk = clk_register_mux(NULL, "spdif_in_mclk", spdif_in_parents,
                        ARRAY_SIZE(spdif_in_parents), 0,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_IN_CLK_SHIFT,
                        SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "spdif_in_mux_clk", NULL);
+       clk_register_clkdev(clk, "spdif_in_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mux_clk", 0,
+       clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_IN_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spdif-in");
 
-       clk = clk_register_gate(NULL, "acp_clk", "acp_mux_clk", 0,
+       clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0,
                        SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "acp_clk");
 
-       clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mux_clk", 0,
+       clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "plgpio");
 
-       clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mux_clk", 0,
+       clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB,
                        0, &_lock);
        clk_register_clkdev(clk, NULL, "video_dec");
 
-       clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mux_clk", 0,
+       clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_ENC_CLK_ENB,
                        0, &_lock);
        clk_register_clkdev(clk, NULL, "video_enc");
 
-       clk = clk_register_gate(NULL, "video_in_clk", "video_in_mux_clk", 0,
+       clk = clk_register_gate(NULL, "video_in_clk", "video_in_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_IN_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_vip");
 
-       clk = clk_register_gate(NULL, "cam0_clk", "cam0_mux_clk", 0,
+       clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_camif.0");
 
-       clk = clk_register_gate(NULL, "cam1_clk", "cam1_mux_clk", 0,
+       clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_camif.1");
 
-       clk = clk_register_gate(NULL, "cam2_clk", "cam2_mux_clk", 0,
+       clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_camif.2");
 
-       clk = clk_register_gate(NULL, "cam3_clk", "cam3_mux_clk", 0,
+       clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "spear_camif.3");
 
-       clk = clk_register_gate(NULL, "pwm_clk", "pwm_mux_clk", 0,
+       clk = clk_register_gate(NULL, "pwm_clk", "pwm_mclk", 0,
                        SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PWM_CLK_ENB, 0,
                        &_lock);
        clk_register_clkdev(clk, NULL, "pwm");
index 01dd6daff2a1cea564bd892f4efaa3b1e7a586a6..c3157454bb3fc907bb787a7abc9ee5259cf7dce5 100644 (file)
@@ -122,12 +122,12 @@ static struct gpt_rate_tbl gpt_rtbl[] = {
 };
 
 /* clock parents */
-static const char *uart0_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", };
-static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk",
+static const char *uart0_parents[] = { "pll3_clk", "uart_syn_gclk", };
+static const char *firda_parents[] = { "pll3_clk", "firda_syn_gclk",
 };
-static const char *gpt0_parents[] = { "pll3_48m_clk", "gpt0_synth_clk", };
-static const char *gpt1_parents[] = { "pll3_48m_clk", "gpt1_synth_clk", };
-static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", };
+static const char *gpt0_parents[] = { "pll3_clk", "gpt0_syn_clk", };
+static const char *gpt1_parents[] = { "pll3_clk", "gpt1_syn_clk", };
+static const char *gpt2_parents[] = { "pll3_clk", "gpt2_syn_clk", };
 static const char *gen2_3_parents[] = { "pll1_clk", "pll2_clk", };
 static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none",
        "pll2_clk", };
@@ -137,7 +137,7 @@ static void __init spear300_clk_init(void)
 {
        struct clk *clk;
 
-       clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0,
+       clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_clk", 0,
                        1, 1);
        clk_register_clkdev(clk, NULL, "60000000.clcd");
 
@@ -219,15 +219,11 @@ static void __init spear310_clk_init(void)
        #define SPEAR320_UARTX_PCLK_VAL_SYNTH1          0x0
        #define SPEAR320_UARTX_PCLK_VAL_APB             0x1
 
-static const char *i2s_ref_parents[] = { "ras_pll2_clk",
-       "ras_gen2_synth_gate_clk", };
-static const char *sdhci_parents[] = { "ras_pll3_48m_clk",
-       "ras_gen3_synth_gate_clk",
-};
+static const char *i2s_ref_parents[] = { "ras_pll2_clk", "ras_syn2_gclk", };
+static const char *sdhci_parents[] = { "ras_pll3_clk", "ras_syn3_gclk", };
 static const char *smii0_parents[] = { "smii_125m_pad", "ras_pll2_clk",
-       "ras_gen0_synth_gate_clk", };
-static const char *uartx_parents[] = { "ras_gen1_synth_gate_clk", "ras_apb_clk",
-};
+       "ras_syn0_gclk", };
+static const char *uartx_parents[] = { "ras_syn1_gclk", "ras_apb_clk", };
 
 static void __init spear320_clk_init(void)
 {
@@ -237,7 +233,7 @@ static void __init spear320_clk_init(void)
                        CLK_IS_ROOT, 125000000);
        clk_register_clkdev(clk, "smii_125m_pad", NULL);
 
-       clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_48m_clk", 0,
+       clk = clk_register_fixed_factor(NULL, "clcd_clk", "ras_pll3_clk", 0,
                        1, 1);
        clk_register_clkdev(clk, NULL, "90000000.clcd");
 
@@ -363,9 +359,9 @@ void __init spear3xx_clk_init(void)
        clk_register_clkdev(clk, NULL, "fc900000.rtc");
 
        /* clock derived from 24 MHz osc clk */
-       clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0,
+       clk = clk_register_fixed_rate(NULL, "pll3_clk", "osc_24m_clk", 0,
                        48000000);
-       clk_register_clkdev(clk, "pll3_48m_clk", NULL);
+       clk_register_clkdev(clk, "pll3_clk", NULL);
 
        clk = clk_register_fixed_factor(NULL, "wdt_clk", "osc_24m_clk", 0, 1,
                        1);
@@ -392,98 +388,98 @@ void __init spear3xx_clk_init(void)
                        HCLK_RATIO_MASK, 0, &_lock);
        clk_register_clkdev(clk, "ahb_clk", NULL);
 
-       clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk",
-                       "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl,
-                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "uart_synth_clk", NULL);
-       clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL);
+       clk = clk_register_aux("uart_syn_clk", "uart_syn_gclk", "pll1_clk", 0,
+                       UART_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl),
+                       &_lock, &clk1);
+       clk_register_clkdev(clk, "uart_syn_clk", NULL);
+       clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "uart0_mux_clk", uart0_parents,
+       clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
                        ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG,
                        UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "uart0_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart0_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart0", "uart0_mux_clk", 0,
-                       PERIP1_CLK_ENB, UART_CLK_ENB, 0, &_lock);
+       clk = clk_register_gate(NULL, "uart0", "uart0_mclk", 0, PERIP1_CLK_ENB,
+                       UART_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "d0000000.serial");
 
-       clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk",
-                       "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl,
-                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "firda_synth_clk", NULL);
-       clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL);
+       clk = clk_register_aux("firda_syn_clk", "firda_syn_gclk", "pll1_clk", 0,
+                       FIRDA_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl),
+                       &_lock, &clk1);
+       clk_register_clkdev(clk, "firda_syn_clk", NULL);
+       clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents,
+       clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
                        ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG,
                        FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "firda_mux_clk", NULL);
+       clk_register_clkdev(clk, "firda_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0,
+       clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0,
                        PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "firda");
 
        /* gpt clocks */
-       clk_register_gpt("gpt0_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG,
-                       gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock);
+       clk_register_gpt("gpt0_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl,
+                       ARRAY_SIZE(gpt_rtbl), &_lock);
        clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents,
                        ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG,
                        GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt0");
 
-       clk_register_gpt("gpt1_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG,
-                       gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock);
-       clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt1_parents,
+       clk_register_gpt("gpt1_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl,
+                       ARRAY_SIZE(gpt_rtbl), &_lock);
+       clk = clk_register_mux(NULL, "gpt1_mclk", gpt1_parents,
                        ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG,
                        GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gpt1_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt1_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
                        PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt1");
 
-       clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG,
-                       gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock);
-       clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents,
+       clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl,
+                       ARRAY_SIZE(gpt_rtbl), &_lock);
+       clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
                        ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG,
                        GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gpt2_mux_clk", NULL);
-       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0,
+       clk_register_clkdev(clk, "gpt2_mclk", NULL);
+       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
                        PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt2");
 
        /* general synths clocks */
-       clk = clk_register_aux("gen0_synth_clk", "gen0_synth_gate_clk",
-                       "pll1_clk", 0, GEN0_CLK_SYNT, NULL, aux_rtbl,
-                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "gen0_synth_clk", NULL);
-       clk_register_clkdev(clk1, "gen0_synth_gate_clk", NULL);
-
-       clk = clk_register_aux("gen1_synth_clk", "gen1_synth_gate_clk",
-                       "pll1_clk", 0, GEN1_CLK_SYNT, NULL, aux_rtbl,
-                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "gen1_synth_clk", NULL);
-       clk_register_clkdev(clk1, "gen1_synth_gate_clk", NULL);
-
-       clk = clk_register_mux(NULL, "gen2_3_parent_clk", gen2_3_parents,
+       clk = clk_register_aux("gen0_syn_clk", "gen0_syn_gclk", "pll1_clk",
+                       0, GEN0_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl),
+                       &_lock, &clk1);
+       clk_register_clkdev(clk, "gen0_syn_clk", NULL);
+       clk_register_clkdev(clk1, "gen0_syn_gclk", NULL);
+
+       clk = clk_register_aux("gen1_syn_clk", "gen1_syn_gclk", "pll1_clk",
+                       0, GEN1_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl),
+                       &_lock, &clk1);
+       clk_register_clkdev(clk, "gen1_syn_clk", NULL);
+       clk_register_clkdev(clk1, "gen1_syn_gclk", NULL);
+
+       clk = clk_register_mux(NULL, "gen2_3_par_clk", gen2_3_parents,
                        ARRAY_SIZE(gen2_3_parents), 0, CORE_CLK_CFG,
                        GEN_SYNTH2_3_CLK_SHIFT, GEN_SYNTH2_3_CLK_MASK, 0,
                        &_lock);
-       clk_register_clkdev(clk, "gen2_3_parent_clk", NULL);
+       clk_register_clkdev(clk, "gen2_3_par_clk", NULL);
 
-       clk = clk_register_aux("gen2_synth_clk", "gen2_synth_gate_clk",
-                       "gen2_3_parent_clk", 0, GEN2_CLK_SYNT, NULL, aux_rtbl,
+       clk = clk_register_aux("gen2_syn_clk", "gen2_syn_gclk",
+                       "gen2_3_par_clk", 0, GEN2_CLK_SYNT, NULL, aux_rtbl,
                        ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "gen2_synth_clk", NULL);
-       clk_register_clkdev(clk1, "gen2_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "gen2_syn_clk", NULL);
+       clk_register_clkdev(clk1, "gen2_syn_gclk", NULL);
 
-       clk = clk_register_aux("gen3_synth_clk", "gen3_synth_gate_clk",
-                       "gen2_3_parent_clk", 0, GEN3_CLK_SYNT, NULL, aux_rtbl,
+       clk = clk_register_aux("gen3_syn_clk", "gen3_syn_gclk",
+                       "gen2_3_par_clk", 0, GEN3_CLK_SYNT, NULL, aux_rtbl,
                        ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "gen3_synth_clk", NULL);
-       clk_register_clkdev(clk1, "gen3_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "gen3_syn_clk", NULL);
+       clk_register_clkdev(clk1, "gen3_syn_gclk", NULL);
 
        /* clock derived from pll3 clk */
-       clk = clk_register_gate(NULL, "usbh_clk", "pll3_48m_clk", 0,
-                       PERIP1_CLK_ENB, USBH_CLK_ENB, 0, &_lock);
+       clk = clk_register_gate(NULL, "usbh_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
+                       USBH_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, "usbh_clk", NULL);
 
        clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1,
@@ -494,8 +490,8 @@ void __init spear3xx_clk_init(void)
                        1);
        clk_register_clkdev(clk, "usbh.1_clk", NULL);
 
-       clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0,
-                       PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock);
+       clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
+                       USBD_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "designware_udc");
 
        /* clock derived from ahb clk */
@@ -579,29 +575,25 @@ void __init spear3xx_clk_init(void)
                        RAS_CLK_ENB, RAS_PLL2_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, "ras_pll2_clk", NULL);
 
-       clk = clk_register_gate(NULL, "ras_pll3_48m_clk", "pll3_48m_clk", 0,
+       clk = clk_register_gate(NULL, "ras_pll3_clk", "pll3_clk", 0,
                        RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock);
-       clk_register_clkdev(clk, "ras_pll3_48m_clk", NULL);
-
-       clk = clk_register_gate(NULL, "ras_gen0_synth_gate_clk",
-                       "gen0_synth_gate_clk", 0, RAS_CLK_ENB,
-                       RAS_SYNT0_CLK_ENB, 0, &_lock);
-       clk_register_clkdev(clk, "ras_gen0_synth_gate_clk", NULL);
-
-       clk = clk_register_gate(NULL, "ras_gen1_synth_gate_clk",
-                       "gen1_synth_gate_clk", 0, RAS_CLK_ENB,
-                       RAS_SYNT1_CLK_ENB, 0, &_lock);
-       clk_register_clkdev(clk, "ras_gen1_synth_gate_clk", NULL);
-
-       clk = clk_register_gate(NULL, "ras_gen2_synth_gate_clk",
-                       "gen2_synth_gate_clk", 0, RAS_CLK_ENB,
-                       RAS_SYNT2_CLK_ENB, 0, &_lock);
-       clk_register_clkdev(clk, "ras_gen2_synth_gate_clk", NULL);
-
-       clk = clk_register_gate(NULL, "ras_gen3_synth_gate_clk",
-                       "gen3_synth_gate_clk", 0, RAS_CLK_ENB,
-                       RAS_SYNT3_CLK_ENB, 0, &_lock);
-       clk_register_clkdev(clk, "ras_gen3_synth_gate_clk", NULL);
+       clk_register_clkdev(clk, "ras_pll3_clk", NULL);
+
+       clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk", 0,
+                       RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0, &_lock);
+       clk_register_clkdev(clk, "ras_syn0_gclk", NULL);
+
+       clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk", 0,
+                       RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0, &_lock);
+       clk_register_clkdev(clk, "ras_syn1_gclk", NULL);
+
+       clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk", 0,
+                       RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0, &_lock);
+       clk_register_clkdev(clk, "ras_syn2_gclk", NULL);
+
+       clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk", 0,
+                       RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0, &_lock);
+       clk_register_clkdev(clk, "ras_syn3_gclk", NULL);
 
        if (of_machine_is_compatible("st,spear300"))
                spear300_clk_init();
index 61026ae564ab95276b39f302184032c886599d38..a98d0866f5416b4dab5d4073362f37c91825d873 100644 (file)
@@ -97,13 +97,12 @@ static struct aux_rate_tbl aux_rtbl[] = {
        {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */
 };
 
-static const char *clcd_parents[] = { "pll3_48m_clk", "clcd_synth_gate_clk", };
-static const char *firda_parents[] = { "pll3_48m_clk", "firda_synth_gate_clk",
-};
-static const char *uart_parents[] = { "pll3_48m_clk", "uart_synth_gate_clk", };
-static const char *gpt0_1_parents[] = { "pll3_48m_clk", "gpt0_1_synth_clk", };
-static const char *gpt2_parents[] = { "pll3_48m_clk", "gpt2_synth_clk", };
-static const char *gpt3_parents[] = { "pll3_48m_clk", "gpt3_synth_clk", };
+static const char *clcd_parents[] = { "pll3_clk", "clcd_syn_gclk", };
+static const char *firda_parents[] = { "pll3_clk", "firda_syn_gclk", };
+static const char *uart_parents[] = { "pll3_clk", "uart_syn_gclk", };
+static const char *gpt0_1_parents[] = { "pll3_clk", "gpt0_1_syn_clk", };
+static const char *gpt2_parents[] = { "pll3_clk", "gpt2_syn_clk", };
+static const char *gpt3_parents[] = { "pll3_clk", "gpt3_syn_clk", };
 static const char *ddr_parents[] = { "ahb_clk", "ahbmult2_clk", "none",
        "pll2_clk", };
 
@@ -136,9 +135,9 @@ void __init spear6xx_clk_init(void)
        clk_register_clkdev(clk, NULL, "rtc-spear");
 
        /* clock derived from 30 MHz osc clk */
-       clk = clk_register_fixed_rate(NULL, "pll3_48m_clk", "osc_24m_clk", 0,
+       clk = clk_register_fixed_rate(NULL, "pll3_clk", "osc_24m_clk", 0,
                        48000000);
-       clk_register_clkdev(clk, "pll3_48m_clk", NULL);
+       clk_register_clkdev(clk, "pll3_clk", NULL);
 
        clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "osc_30m_clk",
                        0, PLL1_CTR, PLL1_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl),
@@ -146,9 +145,9 @@ void __init spear6xx_clk_init(void)
        clk_register_clkdev(clk, "vco1_clk", NULL);
        clk_register_clkdev(clk1, "pll1_clk", NULL);
 
-       clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL,
-                       "osc_30m_clk", 0, PLL2_CTR, PLL2_FRQ, pll_rtbl,
-                       ARRAY_SIZE(pll_rtbl), &_lock, &clk1, NULL);
+       clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "osc_30m_clk",
+                       0, PLL2_CTR, PLL2_FRQ, pll_rtbl, ARRAY_SIZE(pll_rtbl),
+                       &_lock, &clk1, NULL);
        clk_register_clkdev(clk, "vco2_clk", NULL);
        clk_register_clkdev(clk1, "pll2_clk", NULL);
 
@@ -165,111 +164,111 @@ void __init spear6xx_clk_init(void)
                        HCLK_RATIO_MASK, 0, &_lock);
        clk_register_clkdev(clk, "ahb_clk", NULL);
 
-       clk = clk_register_aux("uart_synth_clk", "uart_synth_gate_clk",
-                       "pll1_clk", 0, UART_CLK_SYNT, NULL, aux_rtbl,
-                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "uart_synth_clk", NULL);
-       clk_register_clkdev(clk1, "uart_synth_gate_clk", NULL);
+       clk = clk_register_aux("uart_syn_clk", "uart_syn_gclk", "pll1_clk", 0,
+                       UART_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl),
+                       &_lock, &clk1);
+       clk_register_clkdev(clk, "uart_syn_clk", NULL);
+       clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "uart_mux_clk", uart_parents,
+       clk = clk_register_mux(NULL, "uart_mclk", uart_parents,
                        ARRAY_SIZE(uart_parents), 0, PERIP_CLK_CFG,
                        UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "uart_mux_clk", NULL);
+       clk_register_clkdev(clk, "uart_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "uart0", "uart_mux_clk", 0,
-                       PERIP1_CLK_ENB, UART0_CLK_ENB, 0, &_lock);
+       clk = clk_register_gate(NULL, "uart0", "uart_mclk", 0, PERIP1_CLK_ENB,
+                       UART0_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "d0000000.serial");
 
-       clk = clk_register_gate(NULL, "uart1", "uart_mux_clk", 0,
-                       PERIP1_CLK_ENB, UART1_CLK_ENB, 0, &_lock);
+       clk = clk_register_gate(NULL, "uart1", "uart_mclk", 0, PERIP1_CLK_ENB,
+                       UART1_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "d0080000.serial");
 
-       clk = clk_register_aux("firda_synth_clk", "firda_synth_gate_clk",
-                       "pll1_clk", 0, FIRDA_CLK_SYNT, NULL, aux_rtbl,
-                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "firda_synth_clk", NULL);
-       clk_register_clkdev(clk1, "firda_synth_gate_clk", NULL);
+       clk = clk_register_aux("firda_syn_clk", "firda_syn_gclk", "pll1_clk",
+                       0, FIRDA_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl),
+                       &_lock, &clk1);
+       clk_register_clkdev(clk, "firda_syn_clk", NULL);
+       clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "firda_mux_clk", firda_parents,
+       clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
                        ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG,
                        FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "firda_mux_clk", NULL);
+       clk_register_clkdev(clk, "firda_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "firda_clk", "firda_mux_clk", 0,
+       clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0,
                        PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "firda");
 
-       clk = clk_register_aux("clcd_synth_clk", "clcd_synth_gate_clk",
-                       "pll1_clk", 0, CLCD_CLK_SYNT, NULL, aux_rtbl,
-                       ARRAY_SIZE(aux_rtbl), &_lock, &clk1);
-       clk_register_clkdev(clk, "clcd_synth_clk", NULL);
-       clk_register_clkdev(clk1, "clcd_synth_gate_clk", NULL);
+       clk = clk_register_aux("clcd_syn_clk", "clcd_syn_gclk", "pll1_clk",
+                       0, CLCD_CLK_SYNT, NULL, aux_rtbl, ARRAY_SIZE(aux_rtbl),
+                       &_lock, &clk1);
+       clk_register_clkdev(clk, "clcd_syn_clk", NULL);
+       clk_register_clkdev(clk1, "clcd_syn_gclk", NULL);
 
-       clk = clk_register_mux(NULL, "clcd_mux_clk", clcd_parents,
+       clk = clk_register_mux(NULL, "clcd_mclk", clcd_parents,
                        ARRAY_SIZE(clcd_parents), 0, PERIP_CLK_CFG,
                        CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "clcd_mux_clk", NULL);
+       clk_register_clkdev(clk, "clcd_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "clcd_clk", "clcd_mux_clk", 0,
+       clk = clk_register_gate(NULL, "clcd_clk", "clcd_mclk", 0,
                        PERIP1_CLK_ENB, CLCD_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "clcd");
 
        /* gpt clocks */
-       clk = clk_register_gpt("gpt0_1_synth_clk", "pll1_clk", 0, PRSC0_CLK_CFG,
+       clk = clk_register_gpt("gpt0_1_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG,
                        gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock);
-       clk_register_clkdev(clk, "gpt0_1_synth_clk", NULL);
+       clk_register_clkdev(clk, "gpt0_1_syn_clk", NULL);
 
-       clk = clk_register_mux(NULL, "gpt0_mux_clk", gpt0_1_parents,
+       clk = clk_register_mux(NULL, "gpt0_mclk", gpt0_1_parents,
                        ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG,
                        GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt0");
 
-       clk = clk_register_mux(NULL, "gpt1_mux_clk", gpt0_1_parents,
+       clk = clk_register_mux(NULL, "gpt1_mclk", gpt0_1_parents,
                        ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG,
                        GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gpt1_mux_clk", NULL);
+       clk_register_clkdev(clk, "gpt1_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mux_clk", 0,
+       clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
                        PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt1");
 
-       clk = clk_register_gpt("gpt2_synth_clk", "pll1_clk", 0, PRSC1_CLK_CFG,
+       clk = clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG,
                        gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock);
-       clk_register_clkdev(clk, "gpt2_synth_clk", NULL);
+       clk_register_clkdev(clk, "gpt2_syn_clk", NULL);
 
-       clk = clk_register_mux(NULL, "gpt2_mux_clk", gpt2_parents,
+       clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
                        ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG,
                        GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gpt2_mux_clk", NULL);
+       clk_register_clkdev(clk, "gpt2_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mux_clk", 0,
+       clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
                        PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt2");
 
-       clk = clk_register_gpt("gpt3_synth_clk", "pll1_clk", 0, PRSC2_CLK_CFG,
+       clk = clk_register_gpt("gpt3_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG,
                        gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock);
-       clk_register_clkdev(clk, "gpt3_synth_clk", NULL);
+       clk_register_clkdev(clk, "gpt3_syn_clk", NULL);
 
-       clk = clk_register_mux(NULL, "gpt3_mux_clk", gpt3_parents,
+       clk = clk_register_mux(NULL, "gpt3_mclk", gpt3_parents,
                        ARRAY_SIZE(gpt3_parents), 0, PERIP_CLK_CFG,
                        GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
-       clk_register_clkdev(clk, "gpt3_mux_clk", NULL);
+       clk_register_clkdev(clk, "gpt3_mclk", NULL);
 
-       clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mux_clk", 0,
+       clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
                        PERIP1_CLK_ENB, GPT3_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt3");
 
        /* clock derived from pll3 clk */
-       clk = clk_register_gate(NULL, "usbh0_clk", "pll3_48m_clk", 0,
+       clk = clk_register_gate(NULL, "usbh0_clk", "pll3_clk", 0,
                        PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "usbh.0_clk");
 
-       clk = clk_register_gate(NULL, "usbh1_clk", "pll3_48m_clk", 0,
+       clk = clk_register_gate(NULL, "usbh1_clk", "pll3_clk", 0,
                        PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "usbh.1_clk");
 
-       clk = clk_register_gate(NULL, "usbd_clk", "pll3_48m_clk", 0,
-                       PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock);
+       clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
+                       USBD_CLK_ENB, 0, &_lock);
        clk_register_clkdev(clk, NULL, "designware_udc");
 
        /* clock derived from ahb clk */
@@ -278,9 +277,8 @@ void __init spear6xx_clk_init(void)
        clk_register_clkdev(clk, "ahbmult2_clk", NULL);
 
        clk = clk_register_mux(NULL, "ddr_clk", ddr_parents,
-                       ARRAY_SIZE(ddr_parents),
-                       0, PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT,
+                       MCTR_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "ddr_clk", NULL);
 
        clk = clk_register_divider(NULL, "apb_clk", "ahb_clk",
index b3236317358443194f5dd1b23c54adc1baa59e80..d53cd0afc20026c1e409110b47d5646f9995f785 100644 (file)
@@ -16,6 +16,9 @@ config CLKSRC_MMIO
 config DW_APB_TIMER
        bool
 
+config DW_APB_TIMER_OF
+       bool
+
 config ARMADA_370_XP_TIMER
        bool
 
index 022015cbee48e636eaf1b09b3605df9214b05994..b65d0c56ab3523d1f777d37aa17338073220a2b3 100644 (file)
@@ -10,5 +10,6 @@ obj-$(CONFIG_EM_TIMER_STI)    += em_sti.o
 obj-$(CONFIG_CLKBLD_I8253)     += i8253.o
 obj-$(CONFIG_CLKSRC_MMIO)      += mmio.o
 obj-$(CONFIG_DW_APB_TIMER)     += dw_apb_timer.o
+obj-$(CONFIG_DW_APB_TIMER_OF)  += dw_apb_timer_of.o
 obj-$(CONFIG_CLKSRC_DBX500_PRCMU)      += clksrc-dbx500-prcmu.o
 obj-$(CONFIG_ARMADA_370_XP_TIMER)      += time-armada-370-xp.o
similarity index 57%
rename from arch/arm/mach-picoxcell/time.c
rename to drivers/clocksource/dw_apb_timer_of.c
index 2ecba6743b8e66b050f7bb79665878a34878484b..f7dba5b79b44425f72e1cc887edc248634683982 100644 (file)
@@ -1,11 +1,20 @@
 /*
+ * Copyright (C) 2012 Altera Corporation
  * Copyright (c) 2011 Picochip Ltd., Jamie Iles
  *
+ * Modified from mach-picoxcell/time.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.
  *
- * All enquiries to support@picochip.com
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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/dw_apb_timer.h>
 #include <linux/of.h>
@@ -15,8 +24,6 @@
 #include <asm/mach/time.h>
 #include <asm/sched_clock.h>
 
-#include "common.h"
-
 static void timer_get_base_and_rate(struct device_node *np,
                                    void __iomem **base, u32 *rate)
 {
@@ -25,11 +32,12 @@ static void timer_get_base_and_rate(struct device_node *np,
        if (!*base)
                panic("Unable to map regs for %s", np->name);
 
-       if (of_property_read_u32(np, "clock-freq", rate))
-               panic("No clock-freq property for %s", np->name);
+       if (of_property_read_u32(np, "clock-freq", rate) &&
+               of_property_read_u32(np, "clock-frequency", rate))
+               panic("No clock-frequency property for %s", np->name);
 }
 
-static void picoxcell_add_clockevent(struct device_node *event_timer)
+static void add_clockevent(struct device_node *event_timer)
 {
        void __iomem *iobase;
        struct dw_apb_clock_event_device *ced;
@@ -49,7 +57,7 @@ static void picoxcell_add_clockevent(struct device_node *event_timer)
        dw_apb_clockevent_register(ced);
 }
 
-static void picoxcell_add_clocksource(struct device_node *source_timer)
+static void add_clocksource(struct device_node *source_timer)
 {
        void __iomem *iobase;
        struct dw_apb_clocksource *cs;
@@ -67,55 +75,57 @@ static void picoxcell_add_clocksource(struct device_node *source_timer)
 
 static void __iomem *sched_io_base;
 
-static u32 picoxcell_read_sched_clock(void)
+static u32 read_sched_clock(void)
 {
        return __raw_readl(sched_io_base);
 }
 
-static const struct of_device_id picoxcell_rtc_ids[] __initconst = {
+static const struct of_device_id sptimer_ids[] __initconst = {
        { .compatible = "picochip,pc3x2-rtc" },
+       { .compatible = "snps,dw-apb-timer-sp" },
        { /* Sentinel */ },
 };
 
-static void picoxcell_init_sched_clock(void)
+static void init_sched_clock(void)
 {
        struct device_node *sched_timer;
        u32 rate;
 
-       sched_timer = of_find_matching_node(NULL, picoxcell_rtc_ids);
+       sched_timer = of_find_matching_node(NULL, sptimer_ids);
        if (!sched_timer)
                panic("No RTC for sched clock to use");
 
        timer_get_base_and_rate(sched_timer, &sched_io_base, &rate);
        of_node_put(sched_timer);
 
-       setup_sched_clock(picoxcell_read_sched_clock, 32, rate);
+       setup_sched_clock(read_sched_clock, 32, rate);
 }
 
-static const struct of_device_id picoxcell_timer_ids[] __initconst = {
+static const struct of_device_id osctimer_ids[] __initconst = {
        { .compatible = "picochip,pc3x2-timer" },
+       { .compatible = "snps,dw-apb-timer-osc" },
        {},
 };
 
-static void __init picoxcell_timer_init(void)
+static void __init timer_init(void)
 {
        struct device_node *event_timer, *source_timer;
 
-       event_timer = of_find_matching_node(NULL, picoxcell_timer_ids);
+       event_timer = of_find_matching_node(NULL, osctimer_ids);
        if (!event_timer)
                panic("No timer for clockevent");
-       picoxcell_add_clockevent(event_timer);
+       add_clockevent(event_timer);
 
-       source_timer = of_find_matching_node(event_timer, picoxcell_timer_ids);
+       source_timer = of_find_matching_node(event_timer, osctimer_ids);
        if (!source_timer)
                panic("No timer for clocksource");
-       picoxcell_add_clocksource(source_timer);
+       add_clocksource(source_timer);
 
        of_node_put(source_timer);
 
-       picoxcell_init_sched_clock();
+       init_sched_clock();
 }
 
-struct sys_timer picoxcell_timer = {
-       .init = picoxcell_timer_init,
+struct sys_timer dw_apb_timer = {
+       .init = timer_init,
 };
index 7f2f149ae40fd4efa933052aa1caf9e1c3834b45..fb8a5279c5d829898d37336c8b4e023ee55f36a5 100644 (file)
@@ -138,7 +138,7 @@ void disable_cpufreq(void)
 static LIST_HEAD(cpufreq_governor_list);
 static DEFINE_MUTEX(cpufreq_governor_mutex);
 
-struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
+static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
 {
        struct cpufreq_policy *data;
        unsigned long flags;
@@ -162,7 +162,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
        if (!data)
                goto err_out_put_module;
 
-       if (!kobject_get(&data->kobj))
+       if (!sysfs && !kobject_get(&data->kobj))
                goto err_out_put_module;
 
        spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -175,16 +175,35 @@ err_out_unlock:
 err_out:
        return NULL;
 }
+
+struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
+{
+       return __cpufreq_cpu_get(cpu, false);
+}
 EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
 
+static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu)
+{
+       return __cpufreq_cpu_get(cpu, true);
+}
 
-void cpufreq_cpu_put(struct cpufreq_policy *data)
+static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs)
 {
-       kobject_put(&data->kobj);
+       if (!sysfs)
+               kobject_put(&data->kobj);
        module_put(cpufreq_driver->owner);
 }
+
+void cpufreq_cpu_put(struct cpufreq_policy *data)
+{
+       __cpufreq_cpu_put(data, false);
+}
 EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
 
+static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
+{
+       __cpufreq_cpu_put(data, true);
+}
 
 /*********************************************************************
  *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
@@ -617,7 +636,7 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
        struct cpufreq_policy *policy = to_policy(kobj);
        struct freq_attr *fattr = to_attr(attr);
        ssize_t ret = -EINVAL;
-       policy = cpufreq_cpu_get(policy->cpu);
+       policy = cpufreq_cpu_get_sysfs(policy->cpu);
        if (!policy)
                goto no_policy;
 
@@ -631,7 +650,7 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
 
        unlock_policy_rwsem_read(policy->cpu);
 fail:
-       cpufreq_cpu_put(policy);
+       cpufreq_cpu_put_sysfs(policy);
 no_policy:
        return ret;
 }
@@ -642,7 +661,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
        struct cpufreq_policy *policy = to_policy(kobj);
        struct freq_attr *fattr = to_attr(attr);
        ssize_t ret = -EINVAL;
-       policy = cpufreq_cpu_get(policy->cpu);
+       policy = cpufreq_cpu_get_sysfs(policy->cpu);
        if (!policy)
                goto no_policy;
 
@@ -656,7 +675,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
 
        unlock_policy_rwsem_write(policy->cpu);
 fail:
-       cpufreq_cpu_put(policy);
+       cpufreq_cpu_put_sysfs(policy);
 no_policy:
        return ret;
 }
index b243a7ee01f6d51876ca8b8fdc5d6d721ac08bb9..af2d81e10f71dfd1ec2432dba8531292b243932c 100644 (file)
@@ -62,8 +62,18 @@ static int exynos_target(struct cpufreq_policy *policy,
                goto out;
        }
 
-       if (cpufreq_frequency_table_target(policy, freq_table,
-                                          freqs.old, relation, &old_index)) {
+       /*
+        * The policy max have been changed so that we cannot get proper
+        * old_index with cpufreq_frequency_table_target(). Thus, ignore
+        * policy and get the index from the raw freqeuncy table.
+        */
+       for (old_index = 0;
+               freq_table[old_index].frequency != CPUFREQ_TABLE_END;
+               old_index++)
+               if (freq_table[old_index].frequency == freqs.old)
+                       break;
+
+       if (freq_table[old_index].frequency == CPUFREQ_TABLE_END) {
                ret = -EINVAL;
                goto out;
        }
index d90519cec8807da1952825da4e9b3dd9f540bad2..d6a533e68e0f1ec804299f54c22055d6e6e534c9 100644 (file)
@@ -201,6 +201,22 @@ void cpuidle_resume_and_unlock(void)
 
 EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
 
+/* Currently used in suspend/resume path to suspend cpuidle */
+void cpuidle_pause(void)
+{
+       mutex_lock(&cpuidle_lock);
+       cpuidle_uninstall_idle_handler();
+       mutex_unlock(&cpuidle_lock);
+}
+
+/* Currently used in suspend/resume path to resume cpuidle */
+void cpuidle_resume(void)
+{
+       mutex_lock(&cpuidle_lock);
+       cpuidle_install_idle_handler();
+       mutex_unlock(&cpuidle_lock);
+}
+
 /**
  * cpuidle_wrap_enter - performs timekeeping and irqen around enter function
  * @dev: pointer to a valid cpuidle_device object
@@ -265,7 +281,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
        state->power_usage = -1;
        state->flags = 0;
        state->enter = poll_idle;
-       state->disable = 0;
+       state->disabled = false;
 }
 #else
 static void poll_idle_init(struct cpuidle_driver *drv) {}
index 40cd3f3024df4031f65a118a43e147e8e1b678bf..58bf3b1ac9c46035c2a3fae79271954f6d436442 100644 (file)
@@ -16,6 +16,7 @@
 
 static struct cpuidle_driver *cpuidle_curr_driver;
 DEFINE_SPINLOCK(cpuidle_driver_lock);
+int cpuidle_driver_refcount;
 
 static void __cpuidle_register_driver(struct cpuidle_driver *drv)
 {
@@ -89,8 +90,34 @@ void cpuidle_unregister_driver(struct cpuidle_driver *drv)
        }
 
        spin_lock(&cpuidle_driver_lock);
-       cpuidle_curr_driver = NULL;
+
+       if (!WARN_ON(cpuidle_driver_refcount > 0))
+               cpuidle_curr_driver = NULL;
+
        spin_unlock(&cpuidle_driver_lock);
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
+
+struct cpuidle_driver *cpuidle_driver_ref(void)
+{
+       struct cpuidle_driver *drv;
+
+       spin_lock(&cpuidle_driver_lock);
+
+       drv = cpuidle_curr_driver;
+       cpuidle_driver_refcount++;
+
+       spin_unlock(&cpuidle_driver_lock);
+       return drv;
+}
+
+void cpuidle_driver_unref(void)
+{
+       spin_lock(&cpuidle_driver_lock);
+
+       if (!WARN_ON(cpuidle_driver_refcount <= 0))
+               cpuidle_driver_refcount--;
+
+       spin_unlock(&cpuidle_driver_lock);
+}
index 06335756ea14269bcaaeebc14c0089939a49fff0..5b1f2c372c1f1956c73f3548a25f25a82997e9f2 100644 (file)
@@ -281,7 +281,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
         * unless the timer is happening really really soon.
         */
        if (data->expected_us > 5 &&
-               drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0)
+           !drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
+               dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
                data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
 
        /*
@@ -290,8 +291,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
         */
        for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
                struct cpuidle_state *s = &drv->states[i];
+               struct cpuidle_state_usage *su = &dev->states_usage[i];
 
-               if (s->disable)
+               if (s->disabled || su->disable)
                        continue;
                if (s->target_residency > data->predicted_us)
                        continue;
index 88032b4dc6d271e8b75a7242ef8a127d5d74ec49..5f809e337b89d04dde3d2cb3ffee098e6dff6e86 100644 (file)
@@ -217,7 +217,8 @@ struct cpuidle_state_attr {
        struct attribute attr;
        ssize_t (*show)(struct cpuidle_state *, \
                                        struct cpuidle_state_usage *, char *);
-       ssize_t (*store)(struct cpuidle_state *, const char *, size_t);
+       ssize_t (*store)(struct cpuidle_state *, \
+                       struct cpuidle_state_usage *, const char *, size_t);
 };
 
 #define define_one_state_ro(_name, show) \
@@ -233,21 +234,22 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \
        return sprintf(buf, "%u\n", state->_name);\
 }
 
-#define define_store_state_function(_name) \
+#define define_store_state_ull_function(_name) \
 static ssize_t store_state_##_name(struct cpuidle_state *state, \
+               struct cpuidle_state_usage *state_usage, \
                const char *buf, size_t size) \
 { \
-       long value; \
+       unsigned long long value; \
        int err; \
        if (!capable(CAP_SYS_ADMIN)) \
                return -EPERM; \
-       err = kstrtol(buf, 0, &value); \
+       err = kstrtoull(buf, 0, &value); \
        if (err) \
                return err; \
        if (value) \
-               state->disable = 1; \
+               state_usage->_name = 1; \
        else \
-               state->disable = 0; \
+               state_usage->_name = 0; \
        return size; \
 }
 
@@ -273,8 +275,8 @@ define_show_state_ull_function(usage)
 define_show_state_ull_function(time)
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
-define_show_state_function(disable)
-define_store_state_function(disable)
+define_show_state_ull_function(disable)
+define_store_state_ull_function(disable)
 
 define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
@@ -318,10 +320,11 @@ static ssize_t cpuidle_state_store(struct kobject *kobj,
 {
        int ret = -EIO;
        struct cpuidle_state *state = kobj_to_state(kobj);
+       struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
        struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
 
        if (cattr->store)
-               ret = cattr->store(state, buf, size);
+               ret = cattr->store(state, state_usage, buf, size);
 
        return ret;
 }
index 7cac12793a4b092289dd3f34891f4e1f85999151..1c307e1b840c80f2a2bbe6c959a9803afcb77f3e 100644 (file)
@@ -1661,27 +1661,26 @@ static void ux500_cryp_shutdown(struct platform_device *pdev)
 
 }
 
-static int ux500_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+static int ux500_cryp_suspend(struct device *dev)
 {
        int ret;
+       struct platform_device *pdev = to_platform_device(dev);
        struct cryp_device_data *device_data;
        struct resource *res_irq;
        struct cryp_ctx *temp_ctx = NULL;
 
-       dev_dbg(&pdev->dev, "[%s]", __func__);
+       dev_dbg(dev, "[%s]", __func__);
 
        /* Handle state? */
        device_data = platform_get_drvdata(pdev);
        if (!device_data) {
-               dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
-                       __func__);
+               dev_err(dev, "[%s]: platform_get_drvdata() failed!", __func__);
                return -ENOMEM;
        }
 
        res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res_irq)
-               dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
-                       __func__);
+               dev_err(dev, "[%s]: IORESOURCE_IRQ, unavailable", __func__);
        else
                disable_irq(res_irq->start);
 
@@ -1692,32 +1691,32 @@ static int ux500_cryp_suspend(struct platform_device *pdev, pm_message_t state)
 
        if (device_data->current_ctx == ++temp_ctx) {
                if (down_interruptible(&driver_data.device_allocation))
-                       dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
-                                       "failed", __func__);
-               ret = cryp_disable_power(&pdev->dev, device_data, false);
+                       dev_dbg(dev, "[%s]: down_interruptible() failed",
+                               __func__);
+               ret = cryp_disable_power(dev, device_data, false);
 
        } else
-               ret = cryp_disable_power(&pdev->dev, device_data, true);
+               ret = cryp_disable_power(dev, device_data, true);
 
        if (ret)
-               dev_err(&pdev->dev, "[%s]: cryp_disable_power()", __func__);
+               dev_err(dev, "[%s]: cryp_disable_power()", __func__);
 
        return ret;
 }
 
-static int ux500_cryp_resume(struct platform_device *pdev)
+static int ux500_cryp_resume(struct device *dev)
 {
        int ret = 0;
+       struct platform_device *pdev = to_platform_device(dev);
        struct cryp_device_data *device_data;
        struct resource *res_irq;
        struct cryp_ctx *temp_ctx = NULL;
 
-       dev_dbg(&pdev->dev, "[%s]", __func__);
+       dev_dbg(dev, "[%s]", __func__);
 
        device_data = platform_get_drvdata(pdev);
        if (!device_data) {
-               dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
-                       __func__);
+               dev_err(dev, "[%s]: platform_get_drvdata() failed!", __func__);
                return -ENOMEM;
        }
 
@@ -1730,11 +1729,10 @@ static int ux500_cryp_resume(struct platform_device *pdev)
        if (!device_data->current_ctx)
                up(&driver_data.device_allocation);
        else
-               ret = cryp_enable_power(&pdev->dev, device_data, true);
+               ret = cryp_enable_power(dev, device_data, true);
 
        if (ret)
-               dev_err(&pdev->dev, "[%s]: cryp_enable_power() failed!",
-                       __func__);
+               dev_err(dev, "[%s]: cryp_enable_power() failed!", __func__);
        else {
                res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
                if (res_irq)
@@ -1744,15 +1742,16 @@ static int ux500_cryp_resume(struct platform_device *pdev)
        return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(ux500_cryp_pm, ux500_cryp_suspend, ux500_cryp_resume);
+
 static struct platform_driver cryp_driver = {
        .probe  = ux500_cryp_probe,
        .remove = ux500_cryp_remove,
        .shutdown = ux500_cryp_shutdown,
-       .suspend  = ux500_cryp_suspend,
-       .resume   = ux500_cryp_resume,
        .driver = {
                .owner = THIS_MODULE,
                .name  = "cryp1"
+               .pm    = &ux500_cryp_pm,
        }
 };
 
index 6dbb9ec709a388c4fe5c52a6db0441f812110970..08d5032cb56426f939fea9760620e22d7154abc3 100644 (file)
@@ -1894,19 +1894,17 @@ static void ux500_hash_shutdown(struct platform_device *pdev)
 
 /**
  * ux500_hash_suspend - Function that suspends the hash device.
- * @pdev:      The platform device.
- * @state:     -
+ * @dev:       Device to suspend.
  */
-static int ux500_hash_suspend(struct platform_device *pdev, pm_message_t state)
+static int ux500_hash_suspend(struct device *dev)
 {
        int ret;
        struct hash_device_data *device_data;
        struct hash_ctx *temp_ctx = NULL;
 
-       device_data = platform_get_drvdata(pdev);
+       device_data = dev_get_drvdata(dev);
        if (!device_data) {
-               dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
-                               __func__);
+               dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
                return -ENOMEM;
        }
 
@@ -1917,33 +1915,32 @@ static int ux500_hash_suspend(struct platform_device *pdev, pm_message_t state)
 
        if (device_data->current_ctx == ++temp_ctx) {
                if (down_interruptible(&driver_data.device_allocation))
-                       dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
-                                       "failed", __func__);
+                       dev_dbg(dev, "[%s]: down_interruptible() failed",
+                               __func__);
                ret = hash_disable_power(device_data, false);
 
        } else
                ret = hash_disable_power(device_data, true);
 
        if (ret)
-               dev_err(&pdev->dev, "[%s]: hash_disable_power()", __func__);
+               dev_err(dev, "[%s]: hash_disable_power()", __func__);
 
        return ret;
 }
 
 /**
  * ux500_hash_resume - Function that resume the hash device.
- * @pdev:      The platform device.
+ * @dev:       Device to resume.
  */
-static int ux500_hash_resume(struct platform_device *pdev)
+static int ux500_hash_resume(struct device *dev)
 {
        int ret = 0;
        struct hash_device_data *device_data;
        struct hash_ctx *temp_ctx = NULL;
 
-       device_data = platform_get_drvdata(pdev);
+       device_data = dev_get_drvdata(dev);
        if (!device_data) {
-               dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
-                               __func__);
+               dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
                return -ENOMEM;
        }
 
@@ -1958,21 +1955,21 @@ static int ux500_hash_resume(struct platform_device *pdev)
                ret = hash_enable_power(device_data, true);
 
        if (ret)
-               dev_err(&pdev->dev, "[%s]: hash_enable_power() failed!",
-                       __func__);
+               dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
 
        return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(ux500_hash_pm, ux500_hash_suspend, ux500_hash_resume);
+
 static struct platform_driver hash_driver = {
        .probe  = ux500_hash_probe,
        .remove = ux500_hash_remove,
        .shutdown = ux500_hash_shutdown,
-       .suspend  = ux500_hash_suspend,
-       .resume   = ux500_hash_resume,
        .driver = {
                .owner = THIS_MODULE,
                .name  = "hash1",
+               .pm    = &ux500_hash_pm,
        }
 };
 
index c4067d0141f7c083ea9de58c72dc0ea3122ca300..542f0c04b6958037b3cf1c468e7705f779f8e11b 100644 (file)
@@ -136,7 +136,7 @@ config GPIO_MPC8XXX
 
 config GPIO_MSM_V1
        tristate "Qualcomm MSM GPIO v1"
-       depends on GPIOLIB && ARCH_MSM
+       depends on GPIOLIB && ARCH_MSM && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
        help
          Say yes here to support the GPIO interface on ARM v6 based
          Qualcomm MSM chips.  Most of the pins on the MSM can be
index 9e9947cb86a3d4fe29bb018987176275d4476e2c..1077754f8289e37ca639541e8d9dd5936c858e7c 100644 (file)
@@ -98,6 +98,7 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
 
        return 0;
 }
+EXPORT_SYMBOL(devm_gpio_request_one);
 
 /**
  *      devm_gpio_free - free an interrupt
index c337143b18f8f97d1fa80c61d84cfe9149b75aff..c89c4c1e668d97cf170f4fc07dc5911d83cb52d9 100644 (file)
@@ -398,10 +398,12 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev)
        writel(~0, port->base + GPIO_ISR);
 
        if (mxc_gpio_hwtype == IMX21_GPIO) {
-               /* setup one handler for all GPIO interrupts */
-               if (pdev->id == 0)
-                       irq_set_chained_handler(port->irq,
-                                               mx2_gpio_irq_handler);
+               /*
+                * Setup one handler for all GPIO interrupts. Actually setting
+                * the handler is needed only once, but doing it for every port
+                * is more robust and easier.
+                */
+               irq_set_chained_handler(port->irq, mx2_gpio_irq_handler);
        } else {
                /* setup one handler for each entry */
                irq_set_chained_handler(port->irq, mx3_gpio_irq_handler);
index c4ed1722734c9eadb190c0ccaa19a9c2eb3b2d39..4fbc208c32cfa213812f6356323a36a51c37087c 100644 (file)
@@ -174,12 +174,22 @@ static inline void _gpio_dbck_enable(struct gpio_bank *bank)
        if (bank->dbck_enable_mask && !bank->dbck_enabled) {
                clk_enable(bank->dbck);
                bank->dbck_enabled = true;
+
+               __raw_writel(bank->dbck_enable_mask,
+                            bank->base + bank->regs->debounce_en);
        }
 }
 
 static inline void _gpio_dbck_disable(struct gpio_bank *bank)
 {
        if (bank->dbck_enable_mask && bank->dbck_enabled) {
+               /*
+                * Disable debounce before cutting it's clock. If debounce is
+                * enabled but the clock is not, GPIO module seems to be unable
+                * to detect events and generate interrupts at least on OMAP3.
+                */
+               __raw_writel(0, bank->base + bank->regs->debounce_en);
+
                clk_disable(bank->dbck);
                bank->dbck_enabled = false;
        }
@@ -1081,7 +1091,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
        bank->is_mpuio = pdata->is_mpuio;
        bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
        bank->loses_context = pdata->loses_context;
-       bank->get_context_loss_count = pdata->get_context_loss_count;
        bank->regs = pdata->regs;
 #ifdef CONFIG_OF_GPIO
        bank->chip.of_node = of_node_get(node);
@@ -1135,6 +1144,9 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
        omap_gpio_chip_init(bank);
        omap_gpio_show_rev(bank);
 
+       if (bank->loses_context)
+               bank->get_context_loss_count = pdata->get_context_loss_count;
+
        pm_runtime_put(bank->dev);
 
        list_add_tail(&bank->node, &omap_gpio_list);
index 38416be8ba1186c41b90b7dfd5df070ad3b7acee..6064fb376e11638f8900c6b6cfc9282900fff5ec 100644 (file)
@@ -383,8 +383,9 @@ static int __devinit gsta_probe(struct platform_device *dev)
        }
        spin_lock_init(&chip->lock);
        gsta_gpio_setup(chip);
-       for (i = 0; i < GSTA_NR_GPIO; i++)
-               gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
+       if (gpio_pdata)
+               for (i = 0; i < GSTA_NR_GPIO; i++)
+                       gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
 
        /* 384 was used in previous code: be compatible for other drivers */
        err = irq_alloc_descs(-1, 384, GSTA_NR_GPIO, NUMA_NO_NODE);
index c1ad2884f2edb0b79f3894a9a16662e5776bda51..11f29c82253c4af5fca18b09f26923a8aa3a48a3 100644 (file)
@@ -149,6 +149,9 @@ static int __devinit tps65910_gpio_probe(struct platform_device *pdev)
        tps65910_gpio->gpio_chip.set    = tps65910_gpio_set;
        tps65910_gpio->gpio_chip.get    = tps65910_gpio_get;
        tps65910_gpio->gpio_chip.dev = &pdev->dev;
+#ifdef CONFIG_OF_GPIO
+       tps65910_gpio->gpio_chip.of_node = tps65910->dev->of_node;
+#endif
        if (pdata && pdata->gpio_base)
                tps65910_gpio->gpio_chip.base = pdata->gpio_base;
        else
index 92ea5350dfe96dd6907ea235bb55b2d25faac08c..aa61ad2fcaaa6573e1de350a82d08151c0040289 100644 (file)
@@ -89,8 +89,11 @@ static int wm8994_gpio_direction_out(struct gpio_chip *chip,
        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 
+       if (value)
+               value = WM8994_GPN_LVL;
+
        return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
-                              WM8994_GPN_DIR, 0);
+                              WM8994_GPN_DIR | WM8994_GPN_LVL, value);
 }
 
 static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
index 5873e481e5d2dadde3c16e0e0883d8e6e3340dbe..a8743c399e83234c976ebdb4b471542a0645c42d 100644 (file)
@@ -1039,6 +1039,24 @@ mode_in_range(const struct drm_display_mode *mode, struct edid *edid,
        return true;
 }
 
+static bool valid_inferred_mode(const struct drm_connector *connector,
+                               const struct drm_display_mode *mode)
+{
+       struct drm_display_mode *m;
+       bool ok = false;
+
+       list_for_each_entry(m, &connector->probed_modes, head) {
+               if (mode->hdisplay == m->hdisplay &&
+                   mode->vdisplay == m->vdisplay &&
+                   drm_mode_vrefresh(mode) == drm_mode_vrefresh(m))
+                       return false; /* duplicated */
+               if (mode->hdisplay <= m->hdisplay &&
+                   mode->vdisplay <= m->vdisplay)
+                       ok = true;
+       }
+       return ok;
+}
+
 static int
 drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
                        struct detailed_timing *timing)
@@ -1048,7 +1066,8 @@ drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
        struct drm_device *dev = connector->dev;
 
        for (i = 0; i < drm_num_dmt_modes; i++) {
-               if (mode_in_range(drm_dmt_modes + i, edid, timing)) {
+               if (mode_in_range(drm_dmt_modes + i, edid, timing) &&
+                   valid_inferred_mode(connector, drm_dmt_modes + i)) {
                        newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]);
                        if (newmode) {
                                drm_mode_probed_add(connector, newmode);
@@ -1088,7 +1107,8 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
                        return modes;
 
                fixup_mode_1366x768(newmode);
-               if (!mode_in_range(newmode, edid, timing)) {
+               if (!mode_in_range(newmode, edid, timing) ||
+                   !valid_inferred_mode(connector, newmode)) {
                        drm_mode_destroy(dev, newmode);
                        continue;
                }
@@ -1116,7 +1136,8 @@ drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid,
                        return modes;
 
                fixup_mode_1366x768(newmode);
-               if (!mode_in_range(newmode, edid, timing)) {
+               if (!mode_in_range(newmode, edid, timing) ||
+                   !valid_inferred_mode(connector, newmode)) {
                        drm_mode_destroy(dev, newmode);
                        continue;
                }
index 9764045428ce345a98721cc3e521804ab9b0e608..b7e7b49d8f627b77c290bf9491c87d508b7e3377 100644 (file)
@@ -78,21 +78,6 @@ static int cdv_backlight_combination_mode(struct drm_device *dev)
        return REG_READ(BLC_PWM_CTL2) & PWM_LEGACY_MODE;
 }
 
-static int cdv_get_brightness(struct backlight_device *bd)
-{
-       struct drm_device *dev = bl_get_data(bd);
-       u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
-
-       if (cdv_backlight_combination_mode(dev)) {
-               u8 lbpc;
-
-               val &= ~1;
-               pci_read_config_byte(dev->pdev, 0xF4, &lbpc);
-               val *= lbpc;
-       }
-       return val;
-}
-
 static u32 cdv_get_max_backlight(struct drm_device *dev)
 {
        u32 max = REG_READ(BLC_PWM_CTL);
@@ -110,6 +95,22 @@ static u32 cdv_get_max_backlight(struct drm_device *dev)
        return max;
 }
 
+static int cdv_get_brightness(struct backlight_device *bd)
+{
+       struct drm_device *dev = bl_get_data(bd);
+       u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+
+       if (cdv_backlight_combination_mode(dev)) {
+               u8 lbpc;
+
+               val &= ~1;
+               pci_read_config_byte(dev->pdev, 0xF4, &lbpc);
+               val *= lbpc;
+       }
+       return (val * 100)/cdv_get_max_backlight(dev);
+
+}
+
 static int cdv_set_brightness(struct backlight_device *bd)
 {
        struct drm_device *dev = bl_get_data(bd);
@@ -120,6 +121,9 @@ static int cdv_set_brightness(struct backlight_device *bd)
        if (level < 1)
                level = 1;
 
+       level *= cdv_get_max_backlight(dev);
+       level /= 100;
+
        if (cdv_backlight_combination_mode(dev)) {
                u32 max = cdv_get_max_backlight(dev);
                u8 lbpc;
@@ -157,7 +161,6 @@ static int cdv_backlight_init(struct drm_device *dev)
 
        cdv_backlight_device->props.brightness =
                        cdv_get_brightness(cdv_backlight_device);
-       cdv_backlight_device->props.max_brightness = cdv_get_max_backlight(dev);
        backlight_update_status(cdv_backlight_device);
        dev_priv->backlight_device = cdv_backlight_device;
        return 0;
index 4f186eca3a3039dc804775a80e55f461c2ff7792..c430bd424681c0b28625972a796aeb96b0524423 100644 (file)
@@ -144,6 +144,8 @@ struct opregion_asle {
 
 #define ASLE_CBLV_VALID         (1<<31)
 
+static struct psb_intel_opregion *system_opregion;
+
 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
@@ -205,7 +207,7 @@ void psb_intel_opregion_enable_asle(struct drm_device *dev)
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct opregion_asle *asle = dev_priv->opregion.asle;
 
-       if (asle) {
+       if (asle && system_opregion ) {
                /* Don't do this on Medfield or other non PC like devices, they
                   use the bit for something different altogether */
                psb_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
@@ -221,7 +223,6 @@ void psb_intel_opregion_enable_asle(struct drm_device *dev)
 #define ACPI_EV_LID            (1<<1)
 #define ACPI_EV_DOCK           (1<<2)
 
-static struct psb_intel_opregion *system_opregion;
 
 static int psb_intel_opregion_video_event(struct notifier_block *nb,
                                          unsigned long val, void *data)
@@ -266,9 +267,6 @@ void psb_intel_opregion_init(struct drm_device *dev)
                system_opregion = opregion;
                register_acpi_notifier(&psb_intel_opregion_notifier);
        }
-
-       if (opregion->asle)
-               psb_intel_opregion_enable_asle(dev);
 }
 
 void psb_intel_opregion_fini(struct drm_device *dev)
index 72dc6b9212656d67a4356149aede32c5691d4e60..4a90f8b0e16cb122ac0ebd62c6b8ddfcd9df9783 100644 (file)
@@ -27,6 +27,7 @@ extern void psb_intel_opregion_asle_intr(struct drm_device *dev);
 extern void psb_intel_opregion_init(struct drm_device *dev);
 extern void psb_intel_opregion_fini(struct drm_device *dev);
 extern int psb_intel_opregion_setup(struct drm_device *dev);
+extern void psb_intel_opregion_enable_asle(struct drm_device *dev);
 
 #else
 
@@ -46,4 +47,8 @@ extern inline int psb_intel_opregion_setup(struct drm_device *dev)
 {
        return 0;
 }
+
+extern inline void psb_intel_opregion_enable_asle(struct drm_device *dev)
+{
+}
 #endif
index eff039bf92d40ae37fa1481cb5ec7006036ffae4..5971bc82b765cd87e6b32a347719ee3a5a218a64 100644 (file)
@@ -144,6 +144,10 @@ static int psb_backlight_init(struct drm_device *dev)
        psb_backlight_device->props.max_brightness = 100;
        backlight_update_status(psb_backlight_device);
        dev_priv->backlight_device = psb_backlight_device;
+
+       /* This must occur after the backlight is properly initialised */
+       psb_lid_timer_init(dev_priv);
+
        return 0;
 }
 
@@ -354,13 +358,6 @@ static int psb_chip_setup(struct drm_device *dev)
        return 0;
 }
 
-/* Not exactly an erratum more an irritation */
-static void psb_chip_errata(struct drm_device *dev)
-{
-       struct drm_psb_private *dev_priv = dev->dev_private;
-       psb_lid_timer_init(dev_priv);
-}
-
 static void psb_chip_teardown(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
@@ -379,7 +376,6 @@ const struct psb_ops psb_chip_ops = {
        .sgx_offset = PSB_SGX_OFFSET,
        .chip_setup = psb_chip_setup,
        .chip_teardown = psb_chip_teardown,
-       .errata = psb_chip_errata,
 
        .crtc_helper = &psb_intel_helper_funcs,
        .crtc_funcs = &psb_intel_crtc_funcs,
index caba6e08693cb83119f3f22e32ba8f14e1b4fbdd..a8858a907f47b8ce2944157bbbd6fb1d3b562a10 100644 (file)
@@ -374,6 +374,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
 
        if (ret)
                return ret;
+       psb_intel_opregion_enable_asle(dev);
 #if 0
        /*enable runtime pm at last*/
        pm_runtime_enable(&dev->pdev->dev);
index f94792626b94fadae47303f150e7aff278d371ef..36822b924eb12974f7c73af8fe8368707ab08abf 100644 (file)
@@ -1401,6 +1401,27 @@ i915_mtrr_setup(struct drm_i915_private *dev_priv, unsigned long base,
        }
 }
 
+static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
+{
+       struct apertures_struct *ap;
+       struct pci_dev *pdev = dev_priv->dev->pdev;
+       bool primary;
+
+       ap = alloc_apertures(1);
+       if (!ap)
+               return;
+
+       ap->ranges[0].base = dev_priv->dev->agp->base;
+       ap->ranges[0].size =
+               dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+       primary =
+               pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+
+       remove_conflicting_framebuffers(ap, "inteldrmfb", primary);
+
+       kfree(ap);
+}
+
 /**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
@@ -1446,6 +1467,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                goto free_priv;
        }
 
+       dev_priv->mm.gtt = intel_gtt_get();
+       if (!dev_priv->mm.gtt) {
+               DRM_ERROR("Failed to initialize GTT\n");
+               ret = -ENODEV;
+               goto put_bridge;
+       }
+
+       i915_kick_out_firmware_fb(dev_priv);
+
        pci_set_master(dev->pdev);
 
        /* overlay on gen2 is broken and can't address above 1G */
@@ -1471,13 +1501,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                goto put_bridge;
        }
 
-       dev_priv->mm.gtt = intel_gtt_get();
-       if (!dev_priv->mm.gtt) {
-               DRM_ERROR("Failed to initialize GTT\n");
-               ret = -ENODEV;
-               goto out_rmmap;
-       }
-
        aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
 
        dev_priv->mm.gtt_mapping =
index 59d44937dd9fcc9f1c4350bc590950d5be75175f..84b648a7ddd8cf697fc07fd00a1e2eed39ff46bd 100644 (file)
@@ -289,8 +289,9 @@ int radeon_vm_manager_init(struct radeon_device *rdev)
        rdev->vm_manager.enabled = false;
 
        /* mark first vm as always in use, it's the system one */
+       /* allocate enough for 2 full VM pts */
        r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
-                                     rdev->vm_manager.max_pfn * 8,
+                                     rdev->vm_manager.max_pfn * 8 * 2,
                                      RADEON_GEM_DOMAIN_VRAM);
        if (r) {
                dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n",
@@ -633,7 +634,15 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
        mutex_init(&vm->mutex);
        INIT_LIST_HEAD(&vm->list);
        INIT_LIST_HEAD(&vm->va);
-       vm->last_pfn = 0;
+       /* SI requires equal sized PTs for all VMs, so always set
+        * last_pfn to max_pfn.  cayman allows variable sized
+        * pts so we can grow then as needed.  Once we switch
+        * to two level pts we can unify this again.
+        */
+       if (rdev->family >= CHIP_TAHITI)
+               vm->last_pfn = rdev->vm_manager.max_pfn;
+       else
+               vm->last_pfn = 0;
        /* map the ib pool buffer at 0 in virtual address space, set
         * read only
         */
index f28bd4b7ef980937c88eb54c30b5534adc5abf3b..21ec9f5653cedc94e729e521e8cf62e4b14c2884 100644 (file)
@@ -292,6 +292,7 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
 int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp)
 {
+       struct radeon_device *rdev = dev->dev_private;
        struct drm_radeon_gem_busy *args = data;
        struct drm_gem_object *gobj;
        struct radeon_bo *robj;
@@ -317,13 +318,14 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
                break;
        }
        drm_gem_object_unreference_unlocked(gobj);
-       r = radeon_gem_handle_lockup(robj->rdev, r);
+       r = radeon_gem_handle_lockup(rdev, r);
        return r;
 }
 
 int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *filp)
 {
+       struct radeon_device *rdev = dev->dev_private;
        struct drm_radeon_gem_wait_idle *args = data;
        struct drm_gem_object *gobj;
        struct radeon_bo *robj;
@@ -336,10 +338,10 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
        robj = gem_to_radeon_bo(gobj);
        r = radeon_bo_wait(robj, NULL, false);
        /* callback hw specific functions if any */
-       if (robj->rdev->asic->ioctl_wait_idle)
-               robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj);
+       if (rdev->asic->ioctl_wait_idle)
+               robj->rdev->asic->ioctl_wait_idle(rdev, robj);
        drm_gem_object_unreference_unlocked(gobj);
-       r = radeon_gem_handle_lockup(robj->rdev, r);
+       r = radeon_gem_handle_lockup(rdev, r);
        return r;
 }
 
index c7b61f16ecfd79855315b5ad938499510a2d8b41..0b0279291a73e79109dd95db5ceee4823be1da66 100644 (file)
@@ -2365,12 +2365,12 @@ int si_pcie_gart_enable(struct radeon_device *rdev)
        WREG32(0x15DC, 0);
 
        /* empty context1-15 */
-       /* FIXME start with 1G, once using 2 level pt switch to full
+       /* FIXME start with 4G, once using 2 level pt switch to full
         * vm size space
         */
        /* set vm size, must be a multiple of 4 */
        WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
-       WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, (1 << 30) / RADEON_GPU_PAGE_SIZE);
+       WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
        for (i = 1; i < 16; i++) {
                if (i < 8)
                        WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
index bef04c19276865ec74c06dfddf2cb90e06736c54..3fda8c87f02cd21e4c5eaf16d67010db203aaaf4 100644 (file)
@@ -386,6 +386,7 @@ config HID_MULTITOUCH
          - Unitec Panels
          - XAT optical touch panels
          - Xiroku optical touch panels
+         - Zytronic touch panels
 
          If unsure, say N.
 
index fa10f847f7dbf163ba5856c296690039ba07b242..585344b6d33815632b8d477ebb1f0eb9e7f80818 100644 (file)
@@ -517,6 +517,12 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
+               .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
index 6ac0286b53757cd80e0f8d713b7af7f332497ae3..4c87276c8ddba2f2a6f072cb536e84f8b7a6d256 100644 (file)
@@ -1503,6 +1503,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1995,6 +1998,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
@@ -2089,6 +2093,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
index d1cdd2d284095ea7d140f93822ab3de7a0694b98..32039235cfeea6e9025c2ce6d0eed04f3294b487 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI   0x024c
 #define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO    0x024d
 #define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS    0x024e
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI   0x0262
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO    0x0263
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS    0x0264
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI  0x0239
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO   0x023a
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_DEVICE_ID_CRYSTALTOUCH     0x0006
 #define USB_DEVICE_ID_CRYSTALTOUCH_DUAL        0x0007
 
+#define USB_VENDOR_ID_MADCATZ          0x0738
+#define USB_DEVICE_ID_MADCATZ_BEATPAD  0x4540
+
 #define USB_VENDOR_ID_MCC              0x09db
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
 #define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE       0x0600
 
+#define USB_VENDOR_ID_SENNHEISER       0x1395
+#define USB_DEVICE_ID_SENNHEISER_BTD500USB     0x002c
+
 #define USB_VENDOR_ID_SIGMA_MICRO      0x1c4f
 #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD     0x0002
 
 #define USB_VENDOR_ID_ZYDACRON 0x13EC
 #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL  0x0006
 
+#define USB_VENDOR_ID_ZYTRONIC         0x14c8
+#define USB_DEVICE_ID_ZYTRONIC_ZXY100  0x0005
+
 #define USB_VENDOR_ID_PRIMAX   0x0461
 #define USB_DEVICE_ID_PRIMAX_KEYBOARD  0x4e05
 
index 132b0019365eed9057eeaaf0a3b222eece0853ad..5301006f6c15fb0246d42073c79931259db9312a 100644 (file)
@@ -301,6 +301,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
                               USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
          HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+               USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
+         HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
        {}
 };
 
index 6e3332a99976d669e008131e0851ae8788113749..76479246d4ee35ef537cf66e83fe5c9f1a6683af 100644 (file)
@@ -1048,6 +1048,11 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
                        USB_DEVICE_ID_XIROKU_CSR2) },
 
+       /* Zytronic panels */
+       { .driver_data = MT_CLS_SERIAL,
+               MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC,
+                       USB_DEVICE_ID_ZYTRONIC_ZXY100) },
+
        /* Generic MT device */
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
        { }
index 0597ee604f6e1d096bf1404a6161949df73de154..903eef3d3e10034f8e36974ba4e95ee746438702 100644 (file)
@@ -76,6 +76,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
index 34ad5a27a7e9fcd68b7597f799a99387f421c835..e3fcf81468349ea5de8bd6cb99f1d9a0617dab72 100644 (file)
@@ -929,20 +929,25 @@ static int acpi_power_meter_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int acpi_power_meter_resume(struct acpi_device *device)
+static int acpi_power_meter_resume(struct device *dev)
 {
        struct acpi_power_meter_resource *resource;
 
-       if (!device || !acpi_driver_data(device))
+       if (!dev)
+               return -EINVAL;
+
+       resource = acpi_driver_data(to_acpi_device(dev));
+       if (!resource)
                return -EINVAL;
 
-       resource = acpi_driver_data(device);
        free_capabilities(resource);
        read_capabilities(resource);
 
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, acpi_power_meter_resume);
+
 static struct acpi_driver acpi_power_meter_driver = {
        .name = "power_meter",
        .class = ACPI_POWER_METER_CLASS,
@@ -950,9 +955,9 @@ static struct acpi_driver acpi_power_meter_driver = {
        .ops = {
                .add = acpi_power_meter_add,
                .remove = acpi_power_meter_remove,
-               .resume = acpi_power_meter_resume,
                .notify = acpi_power_meter_notify,
                },
+       .drv.pm = &acpi_power_meter_pm,
 };
 
 /* Module init/exit routines */
index e7701d99f8e8598207a18de6b6ad7f48a0796073..f1de3979181fd22517c1f068a57d4526cb0ce6e8 100644 (file)
@@ -2341,7 +2341,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
 
        /* Start monitoring */
        it87_write_value(data, IT87_REG_CONFIG,
-                        (it87_read_value(data, IT87_REG_CONFIG) & 0x36)
+                        (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
                         | (update_vbat ? 0x41 : 0x01));
 }
 
index 7356b5ec8f6733bd9b4cc9a96f6f790831c60f6b..f2fe8078633b1d6fe996a69b518c3ad1987cff9f 100644 (file)
@@ -33,9 +33,6 @@ static bool force;
 module_param(force, bool, 0444);
 MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
 
-/* PCI-IDs for Northbridge devices not used anywhere else */
-#define PCI_DEVICE_ID_AMD_15H_M10H_NB_F3       0x1403
-
 /* CPUID function 0x80000001, ebx */
 #define CPUID_PKGTYPE_MASK     0xf0000000
 #define CPUID_PKGTYPE_F                0x00000000
@@ -213,7 +210,7 @@ static DEFINE_PCI_DEVICE_TABLE(k10temp_id_table) = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
-       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_NB_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
        {}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
index 61c9cf15fa52ecd50cb1a1b5421c8fef3666f24c..1201a15784c3a0eec329affa6f6edf1546df0b51 100644 (file)
@@ -345,7 +345,7 @@ int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
                spin_lock_init(&hwlock->lock);
                hwlock->bank = bank;
 
-               ret = hwspin_lock_register_single(hwlock, i);
+               ret = hwspin_lock_register_single(hwlock, base_id + i);
                if (ret)
                        goto reg_failed;
        }
@@ -354,7 +354,7 @@ int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
 
 reg_failed:
        while (--i >= 0)
-               hwspin_lock_unregister_single(i);
+               hwspin_lock_unregister_single(base_id + i);
        return ret;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_register);
index 5267ab93d55073e43c53f5fb073d6d8aec438811..a92440dbef078ba18c6c5561a74f7f8265ba72c4 100644 (file)
@@ -965,8 +965,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
        adap->owner     = THIS_MODULE;
        adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adap->algo      = &nmk_i2c_algo;
-       adap->timeout   = pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
-               msecs_to_jiffies(20000);
+       adap->timeout   = msecs_to_jiffies(pdata->timeout);
        snprintf(adap->name, sizeof(adap->name),
                 "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
 
index d0f59c3f87eff08c9af04bd7d13f2b91e6f3ea17..fe95d5464a0251470cb9f094f4e7bc5922f1e3c8 100644 (file)
@@ -96,6 +96,7 @@ static const struct idle_cpu *icpu;
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
 static int intel_idle(struct cpuidle_device *dev,
                        struct cpuidle_driver *drv, int index);
+static int intel_idle_cpu_init(int cpu);
 
 static struct cpuidle_state *cpuidle_state_table;
 
@@ -302,22 +303,35 @@ static void __setup_broadcast_timer(void *arg)
        clockevents_notify(reason, &cpu);
 }
 
-static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
-               unsigned long action, void *hcpu)
+static int cpu_hotplug_notify(struct notifier_block *n,
+                             unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
+       struct cpuidle_device *dev;
 
        switch (action & 0xf) {
        case CPU_ONLINE:
-               smp_call_function_single(hotcpu, __setup_broadcast_timer,
-                       (void *)true, 1);
+
+               if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
+                       smp_call_function_single(hotcpu, __setup_broadcast_timer,
+                                                (void *)true, 1);
+
+               /*
+                * Some systems can hotplug a cpu at runtime after
+                * the kernel has booted, we have to initialize the
+                * driver in this case
+                */
+               dev = per_cpu_ptr(intel_idle_cpuidle_devices, hotcpu);
+               if (!dev->registered)
+                       intel_idle_cpu_init(hotcpu);
+
                break;
        }
        return NOTIFY_OK;
 }
 
-static struct notifier_block setup_broadcast_notifier = {
-       .notifier_call = setup_broadcast_cpuhp_notify,
+static struct notifier_block cpu_hotplug_notifier = {
+       .notifier_call = cpu_hotplug_notify,
 };
 
 static void auto_demotion_disable(void *dummy)
@@ -405,10 +419,10 @@ static int intel_idle_probe(void)
 
        if (boot_cpu_has(X86_FEATURE_ARAT))     /* Always Reliable APIC Timer */
                lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
-       else {
+       else
                on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
-               register_cpu_notifier(&setup_broadcast_notifier);
-       }
+
+       register_cpu_notifier(&cpu_hotplug_notifier);
 
        pr_debug(PREFIX "v" INTEL_IDLE_VERSION
                " model 0x%X\n", boot_cpu_data.x86_model);
@@ -494,7 +508,7 @@ static int intel_idle_cpuidle_driver_init(void)
  * allocate, initialize, register cpuidle_devices
  * @cpu: cpu/core to initialize
  */
-int intel_idle_cpu_init(int cpu)
+static int intel_idle_cpu_init(int cpu)
 {
        int cstate;
        struct cpuidle_device *dev;
@@ -539,7 +553,6 @@ int intel_idle_cpu_init(int cpu)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(intel_idle_cpu_init);
 
 static int __init intel_idle_init(void)
 {
@@ -581,10 +594,10 @@ static void __exit intel_idle_exit(void)
        intel_idle_cpuidle_devices_uninit();
        cpuidle_unregister_driver(&intel_idle_driver);
 
-       if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
+
+       if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
                on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
-               unregister_cpu_notifier(&setup_broadcast_notifier);
-       }
+       unregister_cpu_notifier(&cpu_hotplug_notifier);
 
        return;
 }
index 5c1bc995e5603ced273bc4731ff67ff88eaf6f76..f10221f40803959198a3b85e21b8b57ce01ea60a 100644 (file)
@@ -123,7 +123,7 @@ static void ipoib_ud_skb_put_frags(struct ipoib_dev_priv *priv,
 
                skb_frag_size_set(frag, size);
                skb->data_len += size;
-               skb->truesize += size;
+               skb->truesize += PAGE_SIZE;
        } else
                skb_put(skb, length);
 
@@ -156,14 +156,18 @@ static struct sk_buff *ipoib_alloc_rx_skb(struct net_device *dev, int id)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct sk_buff *skb;
        int buf_size;
+       int tailroom;
        u64 *mapping;
 
-       if (ipoib_ud_need_sg(priv->max_ib_mtu))
+       if (ipoib_ud_need_sg(priv->max_ib_mtu)) {
                buf_size = IPOIB_UD_HEAD_SIZE;
-       else
+               tailroom = 128; /* reserve some tailroom for IP/TCP headers */
+       } else {
                buf_size = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu);
+               tailroom = 0;
+       }
 
-       skb = dev_alloc_skb(buf_size + 4);
+       skb = dev_alloc_skb(buf_size + tailroom + 4);
        if (unlikely(!skb))
                return NULL;
 
index 5f6b7f63cdef28cf37ce3e350c3d5e099d273b16..7a0ce8d42887e225e81d20702892d8ed0d056f39 100644 (file)
@@ -1377,10 +1377,14 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx)
                break;
        case SRPT_STATE_NEED_DATA:
                /* DMA_TO_DEVICE (write) - RDMA read error. */
+
+               /* XXX(hch): this is a horrible layering violation.. */
                spin_lock_irqsave(&ioctx->cmd.t_state_lock, flags);
                ioctx->cmd.transport_state |= CMD_T_LUN_STOP;
+               ioctx->cmd.transport_state &= ~CMD_T_ACTIVE;
                spin_unlock_irqrestore(&ioctx->cmd.t_state_lock, flags);
-               transport_generic_handle_data(&ioctx->cmd);
+
+               complete(&ioctx->cmd.transport_lun_stop_comp);
                break;
        case SRPT_STATE_CMD_RSP_SENT:
                /*
@@ -1463,9 +1467,10 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
 /**
  * srpt_handle_rdma_comp() - Process an IB RDMA completion notification.
  *
- * Note: transport_generic_handle_data() is asynchronous so unmapping the
- * data that has been transferred via IB RDMA must be postponed until the
- * check_stop_free() callback.
+ * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping
+ * the data that has been transferred via IB RDMA had to be postponed until the
+ * check_stop_free() callback.  None of this is nessecary anymore and needs to
+ * be cleaned up.
  */
 static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
                                  struct srpt_send_ioctx *ioctx,
@@ -1477,7 +1482,7 @@ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
        if (opcode == SRPT_RDMA_READ_LAST) {
                if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
                                                SRPT_STATE_DATA_IN))
-                       transport_generic_handle_data(&ioctx->cmd);
+                       target_execute_cmd(&ioctx->cmd);
                else
                        printk(KERN_ERR "%s[%d]: wrong state = %d\n", __func__,
                               __LINE__, srpt_get_cmd_state(ioctx));
index 57d19d4e0a2d94a22f68d13c6f0ee44a9ab8807b..c96653b58867deb406a13913774a7e35c074dec7 100644 (file)
@@ -282,7 +282,8 @@ static int __devinit as5011_probe(struct i2c_client *client,
 
        error = request_threaded_irq(as5011->button_irq,
                                     NULL, as5011_button_interrupt,
-                                    IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                    IRQF_TRIGGER_RISING |
+                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                     "as5011_button", as5011);
        if (error < 0) {
                dev_err(&client->dev,
@@ -296,7 +297,7 @@ static int __devinit as5011_probe(struct i2c_client *client,
 
        error = request_threaded_irq(as5011->axis_irq, NULL,
                                     as5011_axis_interrupt,
-                                    plat_data->axis_irqflags,
+                                    plat_data->axis_irqflags | IRQF_ONESHOT,
                                     "as5011_joystick", as5011);
        if (error) {
                dev_err(&client->dev,
index ee16fb67b7ae235bd9469bc50b9b0f588b99a2e4..83811e45d6339b013cc4f9cc16b90c5c66ba8af8 100644 (file)
@@ -142,6 +142,7 @@ static const struct xpad_device {
        { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
        { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
        { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
+       { 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
        { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
        { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
@@ -164,6 +165,7 @@ static const struct xpad_device {
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
        { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
@@ -238,12 +240,14 @@ static struct usb_device_id xpad_table [] = {
        XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x046d),            /* Logitech X-Box 360 style controllers */
        XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz X-Box 360 controllers */
+       { USB_DEVICE(0x0738, 0x4540) },         /* Mad Catz Beat Pad */
        XPAD_XBOX360_VENDOR(0x0e6f),            /* 0x0e6f X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x12ab),            /* X-Box 360 dance pads */
        XPAD_XBOX360_VENDOR(0x1430),            /* RedOctane X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x146b),            /* BigBen Interactive Controllers */
        XPAD_XBOX360_VENDOR(0x1bad),            /* Harminix Rock Band Guitar and Drums */
-       XPAD_XBOX360_VENDOR(0x0f0d),            /* Hori Controllers */
+       XPAD_XBOX360_VENDOR(0x0f0d),            /* Hori Controllers */
+       XPAD_XBOX360_VENDOR(0x1689),            /* Razer Onza */
        { }
 };
 
index 64a0ca4c92f3376562fe07c8f4855ce889417b1d..0d77f6c84950f7d921e03ae0e078a3c788b72bb6 100644 (file)
@@ -178,7 +178,8 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client,
        }
 
        error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
-                       IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                    client->dev.driver->name, data);
        if (error) {
                dev_err(&client->dev, "Failed to register interrupt\n");
                goto err_free_mem;
index caa218a51b5ac94bd89cade097a41cd926251dcd..7613f1cac9517c1ecf30e18f2946c872c3e25252 100644 (file)
@@ -248,7 +248,7 @@ static int __devinit mpr_touchkey_probe(struct i2c_client *client,
 
        error = request_threaded_irq(client->irq, NULL,
                                     mpr_touchkey_interrupt,
-                                    IRQF_TRIGGER_FALLING,
+                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                     client->dev.driver->name, mpr121);
        if (error) {
                dev_err(&client->dev, "Failed to register interrupt\n");
index 0b7b2f891752061a50ab92745e67e8025c146523..ca68f2992d7292ebdebafc0d6947e201448fc623 100644 (file)
@@ -201,7 +201,8 @@ static int __devinit qt1070_probe(struct i2c_client *client,
        msleep(QT1070_RESET_TIME);
 
        err = request_threaded_irq(client->irq, NULL, qt1070_interrupt,
-               IRQF_TRIGGER_NONE, client->dev.driver->name, data);
+                                  IRQF_TRIGGER_NONE | IRQF_ONESHOT,
+                                  client->dev.driver->name, data);
        if (err) {
                dev_err(&client->dev, "fail to request irq\n");
                goto err_free_mem;
index 3afea3f897182adba5c1439dc38e7a34126fa440..c355cdde8d223e0f7184c297df95d41f3048fb43 100644 (file)
@@ -278,7 +278,8 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client,
 
                error = request_threaded_irq(chip->irqnum, NULL,
                                             tca6416_keys_isr,
-                                            IRQF_TRIGGER_FALLING,
+                                            IRQF_TRIGGER_FALLING |
+                                               IRQF_ONESHOT,
                                             "tca6416-keypad", chip);
                if (error) {
                        dev_dbg(&client->dev,
index 5f87b28b31920b92caf1644413c8cab7fe4da66a..893869b29ed9895c0f1998fbb2068ce7a41ef402 100644 (file)
@@ -360,7 +360,7 @@ static int __devinit tca8418_keypad_probe(struct i2c_client *client,
                client->irq = gpio_to_irq(client->irq);
 
        error = request_threaded_irq(client->irq, NULL, tca8418_irq_handler,
-                                    IRQF_TRIGGER_FALLING,
+                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                     client->name, keypad_data);
        if (error) {
                dev_dbg(&client->dev,
index a4a445fb7020bcf1df98d1a36e958c7e70d83b39..4c34f21fbe2dff4a8b823e48dd96fb4635a81d16 100644 (file)
@@ -227,15 +227,15 @@ static int __devinit keypad_probe(struct platform_device *pdev)
                goto error_clk;
        }
 
-       error = request_threaded_irq(kp->irq_press, NULL, keypad_irq, 0,
-                                    dev_name(dev), kp);
+       error = request_threaded_irq(kp->irq_press, NULL, keypad_irq,
+                                    IRQF_ONESHOT, dev_name(dev), kp);
        if (error < 0) {
                dev_err(kp->dev, "Could not allocate keypad press key irq\n");
                goto error_irq_press;
        }
 
-       error = request_threaded_irq(kp->irq_release, NULL, keypad_irq, 0,
-                                    dev_name(dev), kp);
+       error = request_threaded_irq(kp->irq_release, NULL, keypad_irq,
+                                    IRQF_ONESHOT, dev_name(dev), kp);
        if (error < 0) {
                dev_err(kp->dev, "Could not allocate keypad release key irq\n");
                goto error_irq_release;
index 0ac75bbad4d69d61e64719d1a2550778f121f599..2e5d5e1de64787f17c2349e1a3c575144411518f 100644 (file)
@@ -972,6 +972,7 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
        struct ad714x_platform_data *plat_data = dev->platform_data;
        struct ad714x_chip *ad714x;
        void *drv_mem;
+       unsigned long irqflags;
 
        struct ad714x_button_drv *bt_drv;
        struct ad714x_slider_drv *sd_drv;
@@ -1162,10 +1163,11 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                alloc_idx++;
        }
 
+       irqflags = plat_data->irqflags ?: IRQF_TRIGGER_FALLING;
+       irqflags |= IRQF_ONESHOT;
+
        error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
-                               plat_data->irqflags ?
-                                       plat_data->irqflags : IRQF_TRIGGER_FALLING,
-                               "ad714x_captouch", ad714x);
+                                    irqflags, "ad714x_captouch", ad714x);
        if (error) {
                dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
                goto err_unreg_dev;
index 35083c6836c351ba5110f6fe3ec0cecc98b074e9..c1313d8535c349993f0bb64ba3940ffe3e32b1d2 100644 (file)
@@ -213,7 +213,8 @@ static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
        /* REVISIT:  flush the event queue? */
 
        status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq,
-                       IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), keys);
+                                     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                     dev_name(&pdev->dev), keys);
        if (status < 0)
                goto fail2;
 
index 2cf681d98c0d2d6433a6f8d11c502935d40c202a..d528c23e194f6efcbe7efbe8651d218aa6ef7965 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI  0x0252
 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO   0x0253
 #define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS   0x0254
+/* MacbookPro10,1 (unibody, June 2012) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI   0x0262
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO    0x0263
+#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS    0x0264
 
 #define BCM5974_DEVICE(prod) {                                 \
        .match_flags = (USB_DEVICE_ID_MATCH_DEVICE |            \
@@ -128,6 +132,10 @@ static const struct usb_device_id bcm5974_table[] = {
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
        BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
+       /* MacbookPro10,1 */
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
+       BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
        /* Terminating entry */
        {}
 };
@@ -354,6 +362,18 @@ static const struct bcm5974_config bcm5974_config_table[] = {
                { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
                { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
        },
+       {
+               USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI,
+               USB_DEVICE_ID_APPLE_WELLSPRING7_ISO,
+               USB_DEVICE_ID_APPLE_WELLSPRING7_JIS,
+               HAS_INTEGRATED_BUTTON,
+               0x84, sizeof(struct bt_data),
+               0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+               { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+               { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+               { DIM_X, DIM_X / SN_COORD, -4750, 5280 },
+               { DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+       },
        {}
 };
 
index cad5602d3ce45a525ca70d9cc1cf7f766348c24e..8b31473a81fe9bd6056dd95363405f0e7610c4ee 100644 (file)
@@ -216,7 +216,7 @@ static void wacom_retrieve_report_data(struct usb_interface *intf,
 
                rep_data[0] = 12;
                result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
-                                         rep_data[0], &rep_data, 2,
+                                         rep_data[0], rep_data, 2,
                                          WAC_MSG_RETRIES);
 
                if (result >= 0 && rep_data[1] > 2)
@@ -401,7 +401,9 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                break;
 
                        case HID_USAGE_CONTACTMAX:
-                               wacom_retrieve_report_data(intf, features);
+                               /* leave touch_max as is if predefined */
+                               if (!features->touch_max)
+                                       wacom_retrieve_report_data(intf, features);
                                i++;
                                break;
                        }
index e2482b40da5198fdb1406e135fff827d049e5895..bd4eb42776973b211aee79e40f51b47e2f5e8d27 100644 (file)
@@ -597,7 +597,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
                        AD7879_TMR(ts->pen_down_acc_interval);
 
        err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
-                                  IRQF_TRIGGER_FALLING,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                   dev_name(dev), ts);
        if (err) {
                dev_err(dev, "irq %d busy?\n", ts->irq);
index 42e645062c208e842b6feb5ecaf6824004c49a0c..25fd0561a17d2f1afe83a84c28864e81510acbba 100644 (file)
@@ -1149,7 +1149,8 @@ static int __devinit mxt_probe(struct i2c_client *client,
                goto err_free_object;
 
        error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
-                       pdata->irqflags, client->dev.driver->name, data);
+                                    pdata->irqflags | IRQF_ONESHOT,
+                                    client->dev.driver->name, data);
        if (error) {
                dev_err(&client->dev, "Failed to register interrupt\n");
                goto err_free_object;
index f2d03c06c2da6660c30f64c177164dafb432385f..5c487d23f11cbaedd29e65c5143ba611a90e7d78 100644 (file)
@@ -509,7 +509,8 @@ static int __devinit bu21013_probe(struct i2c_client *client,
        input_set_drvdata(in_dev, bu21013_data);
 
        error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
-                                    IRQF_TRIGGER_FALLING | IRQF_SHARED,
+                                    IRQF_TRIGGER_FALLING | IRQF_SHARED |
+                                       IRQF_ONESHOT,
                                     DRIVER_TP, bu21013_data);
        if (error) {
                dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
index 237753ad10318b9fab24b6d559448ea41d492480..464f1bf4b61dcbf62af90196ba28608b6896e6f8 100644 (file)
@@ -251,7 +251,8 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
        }
 
        err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
-                                  IRQF_TRIGGER_RISING, "touch_reset_key", ts);
+                                  IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                  "touch_reset_key", ts);
        if (err < 0) {
                dev_err(&client->dev,
                        "irq %d busy? error %d\n", client->irq, err);
index 3cd7a837f82b203f41f5ff1aa7cefcf5b3714594..cf299377fc4980e54c02a0bfeb25c41ae2fbc5ec 100644 (file)
@@ -620,7 +620,7 @@ static int __devinit mrstouch_probe(struct platform_device *pdev)
                             MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
 
        err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
-                                  0, "mrstouch", tsdev);
+                                  IRQF_ONESHOT, "mrstouch", tsdev);
        if (err) {
                dev_err(tsdev->dev, "unable to allocate irq\n");
                goto err_free_mem;
index 72f6ba3a470937d2528207d20c53d182a0b7803f..953b4c105cad75ead98062869d7a6c0cc5237068 100644 (file)
@@ -165,7 +165,7 @@ static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
        input_set_drvdata(input, tsdata);
 
        error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
-                                    IRQF_TRIGGER_FALLING,
+                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                     client->name, tsdata);
        if (error) {
                dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
index 7e74880973591bb61daa6e3317a94e43bb8f5415..368d2c6cf780cb0e9a1ffad750bace5a5d6b6e6c 100644 (file)
@@ -297,7 +297,7 @@ static int __devinit tsc_probe(struct platform_device *pdev)
                goto error_clk;
        }
 
-       error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, 0,
+       error = request_threaded_irq(ts->tsc_irq, NULL, tsc_irq, IRQF_ONESHOT,
                                     dev_name(dev), ts);
        if (error < 0) {
                dev_err(ts->dev, "Could not allocate ts irq\n");
index b6adeaee9cc5f0f226781f59ba79961fd9eb1e0b..5ce3fa8ce6465e049dd415b784eaafe7e0fbf7ed 100644 (file)
@@ -650,7 +650,8 @@ static int __devinit tsc2005_probe(struct spi_device *spi)
        tsc2005_stop_scan(ts);
 
        error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
-                                    IRQF_TRIGGER_RISING, "tsc2005", ts);
+                                    IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                    "tsc2005", ts);
        if (error) {
                dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
                goto err_free_mem;
index a2e418cba0ff9df7ebb0c4b5b44361a8987b829c..625626391f2d39d3802710a1677ac49ef3181c9a 100644 (file)
@@ -83,6 +83,8 @@ static struct iommu_ops amd_iommu_ops;
 static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
 int amd_iommu_max_glx_val = -1;
 
+static struct dma_map_ops amd_iommu_dma_ops;
+
 /*
  * general struct to manage commands send to an IOMMU
  */
@@ -402,7 +404,7 @@ static void amd_iommu_stats_init(void)
                return;
 
        de_fflush  = debugfs_create_bool("fullflush", 0444, stats_dir,
-                                        (u32 *)&amd_iommu_unmap_flush);
+                                        &amd_iommu_unmap_flush);
 
        amd_iommu_stats_add(&compl_wait);
        amd_iommu_stats_add(&cnt_map_single);
@@ -2267,6 +2269,13 @@ static int device_change_notifier(struct notifier_block *nb,
                list_add_tail(&dma_domain->list, &iommu_pd_list);
                spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
 
+               dev_data = get_dev_data(dev);
+
+               if (!dev_data->passthrough)
+                       dev->archdata.dma_ops = &amd_iommu_dma_ops;
+               else
+                       dev->archdata.dma_ops = &nommu_dma_ops;
+
                break;
        case BUS_NOTIFY_DEL_DEVICE:
 
index 542024ba6dba2eaccd640dbece64a44222285769..a33612f3206f25f1146df2c84b254b372b306382 100644 (file)
@@ -129,7 +129,7 @@ u16 amd_iommu_last_bdf;                     /* largest PCI device id we have
                                           to handle */
 LIST_HEAD(amd_iommu_unity_map);                /* a list of required unity mappings
                                           we find in ACPI */
-bool amd_iommu_unmap_flush;            /* if true, flush on every unmap */
+u32 amd_iommu_unmap_flush;             /* if true, flush on every unmap */
 
 LIST_HEAD(amd_iommu_list);             /* list of all AMD IOMMUs in the
                                           system */
@@ -1641,6 +1641,8 @@ static int __init amd_iommu_init(void)
 
        amd_iommu_init_api();
 
+       x86_platform.iommu_shutdown = disable_iommus;
+
        if (iommu_pass_through)
                goto out;
 
@@ -1649,8 +1651,6 @@ static int __init amd_iommu_init(void)
        else
                printk(KERN_INFO "AMD-Vi: Lazy IO/TLB flushing enabled\n");
 
-       x86_platform.iommu_shutdown = disable_iommus;
-
 out:
        return ret;
 
index 24355559a2ad23cc98e27d1074bfc5ccfb826a73..c1b1d489817e2b667edbbeb95d36eae1d503a994 100644 (file)
@@ -652,7 +652,7 @@ extern unsigned long *amd_iommu_pd_alloc_bitmap;
  * If true, the addresses will be flushed on unmap time, not when
  * they are reused
  */
-extern bool amd_iommu_unmap_flush;
+extern u32 amd_iommu_unmap_flush;
 
 /* Smallest number of PASIDs supported by any IOMMU in the system */
 extern u32 amd_iommu_max_pasids;
index 3a74e4410fc0737d47e1f294378fdb7dc07e27ad..86e2f4a62b9a95fed887dda18b6bd5bdd2cdacda 100644 (file)
@@ -26,6 +26,8 @@
  * These routines are used by both DMA-remapping and Interrupt-remapping
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* has to precede printk.h */
+
 #include <linux/pci.h>
 #include <linux/dmar.h>
 #include <linux/iova.h>
@@ -39,8 +41,6 @@
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
-#define PREFIX "DMAR: "
-
 /* No locks are needed as DMA remapping hardware unit
  * list is constructed at boot time and hotplug of
  * these units are not supported by the architecture.
@@ -83,16 +83,12 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
                 * ignore it
                 */
                if (!bus) {
-                       printk(KERN_WARNING
-                       PREFIX "Device scope bus [%d] not found\n",
-                       scope->bus);
+                       pr_warn("Device scope bus [%d] not found\n", scope->bus);
                        break;
                }
                pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn));
                if (!pdev) {
-                       printk(KERN_WARNING PREFIX
-                       "Device scope device [%04x:%02x:%02x.%02x] not found\n",
-                               segment, bus->number, path->dev, path->fn);
+                       /* warning will be printed below */
                        break;
                }
                path ++;
@@ -100,9 +96,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
                bus = pdev->subordinate;
        }
        if (!pdev) {
-               printk(KERN_WARNING PREFIX
-               "Device scope device [%04x:%02x:%02x.%02x] not found\n",
-               segment, scope->bus, path->dev, path->fn);
+               pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n",
+                       segment, scope->bus, path->dev, path->fn);
                *dev = NULL;
                return 0;
        }
@@ -110,9 +105,8 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
                        pdev->subordinate) || (scope->entry_type == \
                        ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) {
                pci_dev_put(pdev);
-               printk(KERN_WARNING PREFIX
-                       "Device scope type does not match for %s\n",
-                        pci_name(pdev));
+               pr_warn("Device scope type does not match for %s\n",
+                       pci_name(pdev));
                return -EINVAL;
        }
        *dev = pdev;
@@ -134,8 +128,7 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
                    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
                        (*cnt)++;
                else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
-                       printk(KERN_WARNING PREFIX
-                              "Unsupported device scope\n");
+                       pr_warn("Unsupported device scope\n");
                }
                start += scope->length;
        }
@@ -261,25 +254,23 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
        case ACPI_DMAR_TYPE_HARDWARE_UNIT:
                drhd = container_of(header, struct acpi_dmar_hardware_unit,
                                    header);
-               printk (KERN_INFO PREFIX
-                       "DRHD base: %#016Lx flags: %#x\n",
+               pr_info("DRHD base: %#016Lx flags: %#x\n",
                        (unsigned long long)drhd->address, drhd->flags);
                break;
        case ACPI_DMAR_TYPE_RESERVED_MEMORY:
                rmrr = container_of(header, struct acpi_dmar_reserved_memory,
                                    header);
-               printk (KERN_INFO PREFIX
-                       "RMRR base: %#016Lx end: %#016Lx\n",
+               pr_info("RMRR base: %#016Lx end: %#016Lx\n",
                        (unsigned long long)rmrr->base_address,
                        (unsigned long long)rmrr->end_address);
                break;
        case ACPI_DMAR_TYPE_ATSR:
                atsr = container_of(header, struct acpi_dmar_atsr, header);
-               printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags);
+               pr_info("ATSR flags: %#x\n", atsr->flags);
                break;
        case ACPI_DMAR_HARDWARE_AFFINITY:
                rhsa = container_of(header, struct acpi_dmar_rhsa, header);
-               printk(KERN_INFO PREFIX "RHSA base: %#016Lx proximity domain: %#x\n",
+               pr_info("RHSA base: %#016Lx proximity domain: %#x\n",
                       (unsigned long long)rhsa->base_address,
                       rhsa->proximity_domain);
                break;
@@ -299,7 +290,7 @@ static int __init dmar_table_detect(void)
                                &dmar_tbl_size);
 
        if (ACPI_SUCCESS(status) && !dmar_tbl) {
-               printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
+               pr_warn("Unable to map DMAR\n");
                status = AE_NOT_FOUND;
        }
 
@@ -333,20 +324,18 @@ parse_dmar_table(void)
                return -ENODEV;
 
        if (dmar->width < PAGE_SHIFT - 1) {
-               printk(KERN_WARNING PREFIX "Invalid DMAR haw\n");
+               pr_warn("Invalid DMAR haw\n");
                return -EINVAL;
        }
 
-       printk (KERN_INFO PREFIX "Host address width %d\n",
-               dmar->width + 1);
+       pr_info("Host address width %d\n", dmar->width + 1);
 
        entry_header = (struct acpi_dmar_header *)(dmar + 1);
        while (((unsigned long)entry_header) <
                        (((unsigned long)dmar) + dmar_tbl->length)) {
                /* Avoid looping forever on bad ACPI tables */
                if (entry_header->length == 0) {
-                       printk(KERN_WARNING PREFIX
-                               "Invalid 0-length structure\n");
+                       pr_warn("Invalid 0-length structure\n");
                        ret = -EINVAL;
                        break;
                }
@@ -369,8 +358,7 @@ parse_dmar_table(void)
 #endif
                        break;
                default:
-                       printk(KERN_WARNING PREFIX
-                               "Unknown DMAR structure type %d\n",
+                       pr_warn("Unknown DMAR structure type %d\n",
                                entry_header->type);
                        ret = 0; /* for forward compatibility */
                        break;
@@ -469,12 +457,12 @@ int __init dmar_table_init(void)
        ret = parse_dmar_table();
        if (ret) {
                if (ret != -ENODEV)
-                       printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
+                       pr_info("parse DMAR table failure.\n");
                return ret;
        }
 
        if (list_empty(&dmar_drhd_units)) {
-               printk(KERN_INFO PREFIX "No DMAR devices found\n");
+               pr_info("No DMAR devices found\n");
                return -ENODEV;
        }
 
@@ -506,8 +494,7 @@ int __init check_zero_address(void)
                        (((unsigned long)dmar) + dmar_tbl->length)) {
                /* Avoid looping forever on bad ACPI tables */
                if (entry_header->length == 0) {
-                       printk(KERN_WARNING PREFIX
-                               "Invalid 0-length structure\n");
+                       pr_warn("Invalid 0-length structure\n");
                        return 0;
                }
 
@@ -558,8 +545,7 @@ int __init detect_intel_iommu(void)
 
                if (ret && irq_remapping_enabled && cpu_has_x2apic &&
                    dmar->flags & 0x1)
-                       printk(KERN_INFO
-                              "Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
+                       pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
 
                if (ret && !no_iommu && !iommu_detected && !dmar_disabled) {
                        iommu_detected = 1;
@@ -579,14 +565,89 @@ int __init detect_intel_iommu(void)
 }
 
 
+static void unmap_iommu(struct intel_iommu *iommu)
+{
+       iounmap(iommu->reg);
+       release_mem_region(iommu->reg_phys, iommu->reg_size);
+}
+
+/**
+ * map_iommu: map the iommu's registers
+ * @iommu: the iommu to map
+ * @phys_addr: the physical address of the base resgister
+ *
+ * Memory map the iommu's registers.  Start w/ a single page, and
+ * possibly expand if that turns out to be insufficent.
+ */
+static int map_iommu(struct intel_iommu *iommu, u64 phys_addr)
+{
+       int map_size, err=0;
+
+       iommu->reg_phys = phys_addr;
+       iommu->reg_size = VTD_PAGE_SIZE;
+
+       if (!request_mem_region(iommu->reg_phys, iommu->reg_size, iommu->name)) {
+               pr_err("IOMMU: can't reserve memory\n");
+               err = -EBUSY;
+               goto out;
+       }
+
+       iommu->reg = ioremap(iommu->reg_phys, iommu->reg_size);
+       if (!iommu->reg) {
+               pr_err("IOMMU: can't map the region\n");
+               err = -ENOMEM;
+               goto release;
+       }
+
+       iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
+       iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
+
+       if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
+               err = -EINVAL;
+               warn_invalid_dmar(phys_addr, " returns all ones");
+               goto unmap;
+       }
+
+       /* the registers might be more than one page */
+       map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
+                        cap_max_fault_reg_offset(iommu->cap));
+       map_size = VTD_PAGE_ALIGN(map_size);
+       if (map_size > iommu->reg_size) {
+               iounmap(iommu->reg);
+               release_mem_region(iommu->reg_phys, iommu->reg_size);
+               iommu->reg_size = map_size;
+               if (!request_mem_region(iommu->reg_phys, iommu->reg_size,
+                                       iommu->name)) {
+                       pr_err("IOMMU: can't reserve memory\n");
+                       err = -EBUSY;
+                       goto out;
+               }
+               iommu->reg = ioremap(iommu->reg_phys, iommu->reg_size);
+               if (!iommu->reg) {
+                       pr_err("IOMMU: can't map the region\n");
+                       err = -ENOMEM;
+                       goto release;
+               }
+       }
+       err = 0;
+       goto out;
+
+unmap:
+       iounmap(iommu->reg);
+release:
+       release_mem_region(iommu->reg_phys, iommu->reg_size);
+out:
+       return err;
+}
+
 int alloc_iommu(struct dmar_drhd_unit *drhd)
 {
        struct intel_iommu *iommu;
-       int map_size;
        u32 ver;
        static int iommu_allocated = 0;
        int agaw = 0;
        int msagaw = 0;
+       int err;
 
        if (!drhd->reg_base_addr) {
                warn_invalid_dmar(0, "");
@@ -600,30 +661,22 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        iommu->seq_id = iommu_allocated++;
        sprintf (iommu->name, "dmar%d", iommu->seq_id);
 
-       iommu->reg = ioremap(drhd->reg_base_addr, VTD_PAGE_SIZE);
-       if (!iommu->reg) {
-               printk(KERN_ERR "IOMMU: can't map the region\n");
+       err = map_iommu(iommu, drhd->reg_base_addr);
+       if (err) {
+               pr_err("IOMMU: failed to map %s\n", iommu->name);
                goto error;
        }
-       iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
-       iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
-
-       if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
-               warn_invalid_dmar(drhd->reg_base_addr, " returns all ones");
-               goto err_unmap;
-       }
 
+       err = -EINVAL;
        agaw = iommu_calculate_agaw(iommu);
        if (agaw < 0) {
-               printk(KERN_ERR
-                      "Cannot get a valid agaw for iommu (seq_id = %d)\n",
-                      iommu->seq_id);
+               pr_err("Cannot get a valid agaw for iommu (seq_id = %d)\n",
+                       iommu->seq_id);
                goto err_unmap;
        }
        msagaw = iommu_calculate_max_sagaw(iommu);
        if (msagaw < 0) {
-               printk(KERN_ERR
-                       "Cannot get a valid max agaw for iommu (seq_id = %d)\n",
+               pr_err("Cannot get a valid max agaw for iommu (seq_id = %d)\n",
                        iommu->seq_id);
                goto err_unmap;
        }
@@ -632,19 +685,6 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 
        iommu->node = -1;
 
-       /* the registers might be more than one page */
-       map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
-               cap_max_fault_reg_offset(iommu->cap));
-       map_size = VTD_PAGE_ALIGN(map_size);
-       if (map_size > VTD_PAGE_SIZE) {
-               iounmap(iommu->reg);
-               iommu->reg = ioremap(drhd->reg_base_addr, map_size);
-               if (!iommu->reg) {
-                       printk(KERN_ERR "IOMMU: can't map the region\n");
-                       goto error;
-               }
-       }
-
        ver = readl(iommu->reg + DMAR_VER_REG);
        pr_info("IOMMU %d: reg_base_addr %llx ver %d:%d cap %llx ecap %llx\n",
                iommu->seq_id,
@@ -659,10 +699,10 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        return 0;
 
  err_unmap:
-       iounmap(iommu->reg);
+       unmap_iommu(iommu);
  error:
        kfree(iommu);
-       return -1;
+       return err;
 }
 
 void free_iommu(struct intel_iommu *iommu)
@@ -673,7 +713,8 @@ void free_iommu(struct intel_iommu *iommu)
        free_dmar_iommu(iommu);
 
        if (iommu->reg)
-               iounmap(iommu->reg);
+               unmap_iommu(iommu);
+
        kfree(iommu);
 }
 
@@ -710,7 +751,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index)
        if (fault & DMA_FSTS_IQE) {
                head = readl(iommu->reg + DMAR_IQH_REG);
                if ((head >> DMAR_IQ_SHIFT) == index) {
-                       printk(KERN_ERR "VT-d detected invalid descriptor: "
+                       pr_err("VT-d detected invalid descriptor: "
                                "low=%llx, high=%llx\n",
                                (unsigned long long)qi->desc[index].low,
                                (unsigned long long)qi->desc[index].high);
@@ -1129,15 +1170,14 @@ static int dmar_fault_do_one(struct intel_iommu *iommu, int type,
        reason = dmar_get_fault_reason(fault_reason, &fault_type);
 
        if (fault_type == INTR_REMAP)
-               printk(KERN_ERR "INTR-REMAP: Request device [[%02x:%02x.%d] "
+               pr_err("INTR-REMAP: Request device [[%02x:%02x.%d] "
                       "fault index %llx\n"
                        "INTR-REMAP:[fault reason %02d] %s\n",
                        (source_id >> 8), PCI_SLOT(source_id & 0xFF),
                        PCI_FUNC(source_id & 0xFF), addr >> 48,
                        fault_reason, reason);
        else
-               printk(KERN_ERR
-                      "DMAR:[%s] Request device [%02x:%02x.%d] "
+               pr_err("DMAR:[%s] Request device [%02x:%02x.%d] "
                       "fault addr %llx \n"
                       "DMAR:[fault reason %02d] %s\n",
                       (type ? "DMA Read" : "DMA Write"),
@@ -1157,8 +1197,7 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
        raw_spin_lock_irqsave(&iommu->register_lock, flag);
        fault_status = readl(iommu->reg + DMAR_FSTS_REG);
        if (fault_status)
-               printk(KERN_ERR "DRHD: handling fault status reg %x\n",
-                      fault_status);
+               pr_err("DRHD: handling fault status reg %x\n", fault_status);
 
        /* TBD: ignore advanced fault log currently */
        if (!(fault_status & DMA_FSTS_PPF))
@@ -1224,7 +1263,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
 
        irq = create_irq();
        if (!irq) {
-               printk(KERN_ERR "IOMMU: no free vectors\n");
+               pr_err("IOMMU: no free vectors\n");
                return -EINVAL;
        }
 
@@ -1241,7 +1280,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
 
        ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu);
        if (ret)
-               printk(KERN_ERR "IOMMU: can't request irq\n");
+               pr_err("IOMMU: can't request irq\n");
        return ret;
 }
 
@@ -1258,8 +1297,7 @@ int __init enable_drhd_fault_handling(void)
                ret = dmar_set_interrupt(iommu);
 
                if (ret) {
-                       printk(KERN_ERR "DRHD %Lx: failed to enable fault, "
-                              " interrupt, ret %d\n",
+                       pr_err("DRHD %Lx: failed to enable fault, interrupt, ret %d\n",
                               (unsigned long long)drhd->reg_base_addr, ret);
                        return -1;
                }
index 6d347064b8b0f1a097958907cb402596acdbe0b9..e0b18f3ae9a862a22a8bc2ebe2eccc224c456252 100644 (file)
@@ -902,7 +902,6 @@ static int intel_setup_ioapic_entry(int irq,
        return 0;
 }
 
-#ifdef CONFIG_SMP
 /*
  * Migrate the IO-APIC irq in the presence of intr-remapping.
  *
@@ -924,6 +923,10 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
        struct irq_cfg *cfg = data->chip_data;
        unsigned int dest, irq = data->irq;
        struct irte irte;
+       int err;
+
+       if (!config_enabled(CONFIG_SMP))
+               return -EINVAL;
 
        if (!cpumask_intersects(mask, cpu_online_mask))
                return -EINVAL;
@@ -931,10 +934,16 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
        if (get_irte(irq, &irte))
                return -EBUSY;
 
-       if (assign_irq_vector(irq, cfg, mask))
-               return -EBUSY;
+       err = assign_irq_vector(irq, cfg, mask);
+       if (err)
+               return err;
 
-       dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
+       err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest);
+       if (err) {
+               if (assign_irq_vector(irq, cfg, data->affinity))
+                       pr_err("Failed to recover vector for irq %d\n", irq);
+               return err;
+       }
 
        irte.vector = cfg->vector;
        irte.dest_id = IRTE_DEST(dest);
@@ -956,7 +965,6 @@ intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
        cpumask_copy(data->affinity, mask);
        return 0;
 }
-#endif
 
 static void intel_compose_msi_msg(struct pci_dev *pdev,
                                  unsigned int irq, unsigned int dest,
@@ -1058,9 +1066,7 @@ struct irq_remap_ops intel_irq_remap_ops = {
        .reenable               = reenable_irq_remapping,
        .enable_faulting        = enable_drhd_fault_handling,
        .setup_ioapic_entry     = intel_setup_ioapic_entry,
-#ifdef CONFIG_SMP
        .set_affinity           = intel_ioapic_set_affinity,
-#endif
        .free_irq               = free_irte,
        .compose_msi_msg        = intel_compose_msi_msg,
        .msi_alloc_irq          = intel_msi_alloc_irq,
index 40cda8e98d8748a59fdd47b533445e0ba259e7a2..1d29b1c66e722b473e37c4849da76ca53c2a2121 100644 (file)
@@ -111,16 +111,15 @@ int setup_ioapic_remapped_entry(int irq,
                                             vector, attr);
 }
 
-#ifdef CONFIG_SMP
 int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
                              bool force)
 {
-       if (!remap_ops || !remap_ops->set_affinity)
+       if (!config_enabled(CONFIG_SMP) || !remap_ops ||
+           !remap_ops->set_affinity)
                return 0;
 
        return remap_ops->set_affinity(data, mask, force);
 }
-#endif
 
 void free_remapped_irq(int irq)
 {
index be9d72950c519d422f8114a0981d6e3594f5b5d7..b12974cc1dfe73be3b4366651c26382f1ef8ea23 100644 (file)
@@ -59,11 +59,9 @@ struct irq_remap_ops {
                                  unsigned int, int,
                                  struct io_apic_irq_attr *);
 
-#ifdef CONFIG_SMP
        /* Set the CPU affinity of a remapped interrupt */
        int (*set_affinity)(struct irq_data *data, const struct cpumask *mask,
                            bool force);
-#endif
 
        /* Free an IRQ */
        int (*free_irq)(int);
index ecd679043d7740e6883aae9cbee68da6321fedc1..3f3d09d560ea3c6ce5e3bc7d019e377ac9e63dfe 100644 (file)
@@ -550,13 +550,13 @@ static int alloc_pdir(struct smmu_as *as)
                return 0;
 
        as->pte_count = devm_kzalloc(smmu->dev,
-                    sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_KERNEL);
+                    sizeof(as->pte_count[0]) * SMMU_PDIR_COUNT, GFP_ATOMIC);
        if (!as->pte_count) {
                dev_err(smmu->dev,
                        "failed to allocate smmu_device PTE cunters\n");
                return -ENOMEM;
        }
-       as->pdir_page = alloc_page(GFP_KERNEL | __GFP_DMA);
+       as->pdir_page = alloc_page(GFP_ATOMIC | __GFP_DMA);
        if (!as->pdir_page) {
                dev_err(smmu->dev,
                        "failed to allocate smmu_device page directory\n");
index 1a0ae4445ff2b47c4202359e6bba0b0f5bf8f336..5f21f629b7aebeac0163083a2a83a50f4e53c1a8 100644 (file)
@@ -135,8 +135,8 @@ send_layer2(struct mISDNstack *st, struct sk_buff *skb)
                        skb = NULL;
                else if (*debug & DEBUG_SEND_ERR)
                        printk(KERN_DEBUG
-                              "%s ch%d mgr prim(%x) addr(%x) err %d\n",
-                              __func__, ch->nr, hh->prim, ch->addr, ret);
+                              "%s mgr prim(%x) err %d\n",
+                              __func__, hh->prim, ret);
        }
 out:
        mutex_unlock(&st->lmutex);
index 41dc76db43118a347e4a8a06923b0fd076a12dc3..a019fbb70880bd402aea095b8b90a8ca26a0e66a 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/reboot.h>
 #include "leds.h"
 
+static int panic_heartbeats;
+
 struct heartbeat_trig_data {
        unsigned int phase;
        unsigned int period;
@@ -34,6 +36,11 @@ static void led_heartbeat_function(unsigned long data)
        unsigned long brightness = LED_OFF;
        unsigned long delay = 0;
 
+       if (unlikely(panic_heartbeats)) {
+               led_set_brightness(led_cdev, LED_OFF);
+               return;
+       }
+
        /* acts like an actual heart beat -- ie thump-thump-pause... */
        switch (heartbeat_data->phase) {
        case 0:
@@ -111,12 +118,19 @@ static int heartbeat_reboot_notifier(struct notifier_block *nb,
        return NOTIFY_DONE;
 }
 
+static int heartbeat_panic_notifier(struct notifier_block *nb,
+                                    unsigned long code, void *unused)
+{
+       panic_heartbeats = 1;
+       return NOTIFY_DONE;
+}
+
 static struct notifier_block heartbeat_reboot_nb = {
        .notifier_call = heartbeat_reboot_notifier,
 };
 
 static struct notifier_block heartbeat_panic_nb = {
-       .notifier_call = heartbeat_reboot_notifier,
+       .notifier_call = heartbeat_panic_notifier,
 };
 
 static int __init heartbeat_trig_init(void)
index d039de8322f0a314fca492df4b932289d9033e0d..b58b7a33914abd721e3508835a61afd699221dbf 100644 (file)
@@ -1084,6 +1084,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        ti->split_io = dm_rh_get_region_size(ms->rh);
        ti->num_flush_requests = 1;
        ti->num_discard_requests = 1;
+       ti->discard_zeroes_data_unsupported = 1;
 
        ms->kmirrord_wq = alloc_workqueue("kmirrord",
                                          WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
@@ -1214,7 +1215,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio,
         * We need to dec pending if this was a write.
         */
        if (rw == WRITE) {
-               if (!(bio->bi_rw & REQ_FLUSH))
+               if (!(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD)))
                        dm_rh_dec(ms->rh, map_context->ll);
                return error;
        }
index 7771ed2121820ac50c026f45e2f6c0a288ffba85..69732e03eb3490d636a0183bd22303742ab65c65 100644 (file)
@@ -404,6 +404,9 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio)
                return;
        }
 
+       if (bio->bi_rw & REQ_DISCARD)
+               return;
+
        /* We must inform the log that the sync count has changed. */
        log->type->set_region_sync(log, region, 0);
 
@@ -524,7 +527,7 @@ void dm_rh_inc_pending(struct dm_region_hash *rh, struct bio_list *bios)
        struct bio *bio;
 
        for (bio = bios->head; bio; bio = bio->bi_next) {
-               if (bio->bi_rw & REQ_FLUSH)
+               if (bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))
                        continue;
                rh_inc(rh, dm_rh_bio_to_region(rh, bio));
        }
index 37fdaf81bd1f89abfd28f6a46d2be7ce95f8bcba..68694da0d21d0566a61649339cb3a4f3a3bbc943 100644 (file)
@@ -1245,7 +1245,10 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
 
                        cell_release_singleton(cell, bio);
                        cell_release_singleton(cell2, bio);
-                       remap_and_issue(tc, bio, lookup_result.block);
+                       if ((!lookup_result.shared) && pool->pf.discard_passdown)
+                               remap_and_issue(tc, bio, lookup_result.block);
+                       else
+                               bio_endio(bio, 0);
                }
                break;
 
@@ -2292,6 +2295,13 @@ static int process_reserve_metadata_snap_mesg(unsigned argc, char **argv, struct
        if (r)
                return r;
 
+       r = dm_pool_commit_metadata(pool->pmd);
+       if (r) {
+               DMERR("%s: dm_pool_commit_metadata() failed, error = %d",
+                     __func__, r);
+               return r;
+       }
+
        r = dm_pool_reserve_metadata_snap(pool->pmd);
        if (r)
                DMWARN("reserve_metadata_snap message failed.");
@@ -2621,6 +2631,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
        if (tc->pool->pf.discard_enabled) {
                ti->discards_supported = 1;
                ti->num_discard_requests = 1;
+               ti->discard_zeroes_data_unsupported = 1;
        }
 
        dm_put(pool_md);
index 1c2f9048e1ae010864c4d2478c05f9a510c729e1..d5ab4493c8be656ecd28227994d7f7bbe06b8e2d 100644 (file)
@@ -2931,6 +2931,7 @@ offset_store(struct md_rdev *rdev, const char *buf, size_t len)
                 * can be sane */
                return -EBUSY;
        rdev->data_offset = offset;
+       rdev->new_data_offset = offset;
        return len;
 }
 
@@ -3926,8 +3927,8 @@ array_state_show(struct mddev *mddev, char *page)
        return sprintf(page, "%s\n", array_states[st]);
 }
 
-static int do_md_stop(struct mddev * mddev, int ro, int is_open);
-static int md_set_readonly(struct mddev * mddev, int is_open);
+static int do_md_stop(struct mddev * mddev, int ro, struct block_device *bdev);
+static int md_set_readonly(struct mddev * mddev, struct block_device *bdev);
 static int do_md_run(struct mddev * mddev);
 static int restart_array(struct mddev *mddev);
 
@@ -3943,14 +3944,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
                /* stopping an active array */
                if (atomic_read(&mddev->openers) > 0)
                        return -EBUSY;
-               err = do_md_stop(mddev, 0, 0);
+               err = do_md_stop(mddev, 0, NULL);
                break;
        case inactive:
                /* stopping an active array */
                if (mddev->pers) {
                        if (atomic_read(&mddev->openers) > 0)
                                return -EBUSY;
-                       err = do_md_stop(mddev, 2, 0);
+                       err = do_md_stop(mddev, 2, NULL);
                } else
                        err = 0; /* already inactive */
                break;
@@ -3958,7 +3959,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
                break; /* not supported yet */
        case readonly:
                if (mddev->pers)
-                       err = md_set_readonly(mddev, 0);
+                       err = md_set_readonly(mddev, NULL);
                else {
                        mddev->ro = 1;
                        set_disk_ro(mddev->gendisk, 1);
@@ -3968,7 +3969,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
        case read_auto:
                if (mddev->pers) {
                        if (mddev->ro == 0)
-                               err = md_set_readonly(mddev, 0);
+                               err = md_set_readonly(mddev, NULL);
                        else if (mddev->ro == 1)
                                err = restart_array(mddev);
                        if (err == 0) {
@@ -5351,15 +5352,17 @@ void md_stop(struct mddev *mddev)
 }
 EXPORT_SYMBOL_GPL(md_stop);
 
-static int md_set_readonly(struct mddev *mddev, int is_open)
+static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
 {
        int err = 0;
        mutex_lock(&mddev->open_mutex);
-       if (atomic_read(&mddev->openers) > is_open) {
+       if (atomic_read(&mddev->openers) > !!bdev) {
                printk("md: %s still in use.\n",mdname(mddev));
                err = -EBUSY;
                goto out;
        }
+       if (bdev)
+               sync_blockdev(bdev);
        if (mddev->pers) {
                __md_stop_writes(mddev);
 
@@ -5381,18 +5384,26 @@ out:
  *   0 - completely stop and dis-assemble array
  *   2 - stop but do not disassemble array
  */
-static int do_md_stop(struct mddev * mddev, int mode, int is_open)
+static int do_md_stop(struct mddev * mddev, int mode,
+                     struct block_device *bdev)
 {
        struct gendisk *disk = mddev->gendisk;
        struct md_rdev *rdev;
 
        mutex_lock(&mddev->open_mutex);
-       if (atomic_read(&mddev->openers) > is_open ||
+       if (atomic_read(&mddev->openers) > !!bdev ||
            mddev->sysfs_active) {
                printk("md: %s still in use.\n",mdname(mddev));
                mutex_unlock(&mddev->open_mutex);
                return -EBUSY;
        }
+       if (bdev)
+               /* It is possible IO was issued on some other
+                * open file which was closed before we took ->open_mutex.
+                * As that was not the last close __blkdev_put will not
+                * have called sync_blockdev, so we must.
+                */
+               sync_blockdev(bdev);
 
        if (mddev->pers) {
                if (mddev->ro)
@@ -5466,7 +5477,7 @@ static void autorun_array(struct mddev *mddev)
        err = do_md_run(mddev);
        if (err) {
                printk(KERN_WARNING "md: do_md_run() returned %d\n", err);
-               do_md_stop(mddev, 0, 0);
+               do_md_stop(mddev, 0, NULL);
        }
 }
 
@@ -5784,8 +5795,7 @@ static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)
                        super_types[mddev->major_version].
                                validate_super(mddev, rdev);
                if ((info->state & (1<<MD_DISK_SYNC)) &&
-                   (!test_bit(In_sync, &rdev->flags) ||
-                    rdev->raid_disk != info->raid_disk)) {
+                    rdev->raid_disk != info->raid_disk) {
                        /* This was a hot-add request, but events doesn't
                         * match, so reject it.
                         */
@@ -6482,11 +6492,11 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                        goto done_unlock;
 
                case STOP_ARRAY:
-                       err = do_md_stop(mddev, 0, 1);
+                       err = do_md_stop(mddev, 0, bdev);
                        goto done_unlock;
 
                case STOP_ARRAY_RO:
-                       err = md_set_readonly(mddev, 1);
+                       err = md_set_readonly(mddev, bdev);
                        goto done_unlock;
 
                case BLKROSET:
@@ -6751,7 +6761,7 @@ struct md_thread *md_register_thread(void (*run) (struct mddev *), struct mddev
        thread->tsk = kthread_run(md_thread, thread,
                                  "%s_%s",
                                  mdname(thread->mddev),
-                                 name ?: mddev->pers->name);
+                                 name);
        if (IS_ERR(thread->tsk)) {
                kfree(thread);
                return NULL;
@@ -7298,6 +7308,7 @@ void md_do_sync(struct mddev *mddev)
        int skipped = 0;
        struct md_rdev *rdev;
        char *desc;
+       struct blk_plug plug;
 
        /* just incase thread restarts... */
        if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
@@ -7447,6 +7458,7 @@ void md_do_sync(struct mddev *mddev)
        }
        mddev->curr_resync_completed = j;
 
+       blk_start_plug(&plug);
        while (j < max_sectors) {
                sector_t sectors;
 
@@ -7552,6 +7564,7 @@ void md_do_sync(struct mddev *mddev)
         * this also signals 'finished resyncing' to md_stop
         */
  out:
+       blk_finish_plug(&plug);
        wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
 
        /* tell personality that we are finished */
index 9339e67fcc79a9f961d016d3f80291ce012323bb..61a1833ebaf33ec40afaf752db9a849439c9bd13 100644 (file)
@@ -474,7 +474,8 @@ static int multipath_run (struct mddev *mddev)
        }
 
        {
-               mddev->thread = md_register_thread(multipathd, mddev, NULL);
+               mddev->thread = md_register_thread(multipathd, mddev,
+                                                  "multipath");
                if (!mddev->thread) {
                        printk(KERN_ERR "multipath: couldn't allocate thread"
                                " for %s\n", mdname(mddev));
index 50ed53bf4aa2b1efe1136c2520067ece16bb9b35..fc90c11620adb026c9842d6e95497248d02556e8 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/device-mapper.h>
 #include <linux/export.h>
+#include <linux/vmalloc.h>
 
 #ifdef CONFIG_DM_DEBUG_SPACE_MAPS
 
@@ -89,13 +90,23 @@ static int ca_create(struct count_array *ca, struct dm_space_map *sm)
 
        ca->nr = nr_blocks;
        ca->nr_free = nr_blocks;
-       ca->counts = kzalloc(sizeof(*ca->counts) * nr_blocks, GFP_KERNEL);
-       if (!ca->counts)
-               return -ENOMEM;
+
+       if (!nr_blocks)
+               ca->counts = NULL;
+       else {
+               ca->counts = vzalloc(sizeof(*ca->counts) * nr_blocks);
+               if (!ca->counts)
+                       return -ENOMEM;
+       }
 
        return 0;
 }
 
+static void ca_destroy(struct count_array *ca)
+{
+       vfree(ca->counts);
+}
+
 static int ca_load(struct count_array *ca, struct dm_space_map *sm)
 {
        int r;
@@ -126,12 +137,14 @@ static int ca_load(struct count_array *ca, struct dm_space_map *sm)
 static int ca_extend(struct count_array *ca, dm_block_t extra_blocks)
 {
        dm_block_t nr_blocks = ca->nr + extra_blocks;
-       uint32_t *counts = kzalloc(sizeof(*counts) * nr_blocks, GFP_KERNEL);
+       uint32_t *counts = vzalloc(sizeof(*counts) * nr_blocks);
        if (!counts)
                return -ENOMEM;
 
-       memcpy(counts, ca->counts, sizeof(*counts) * ca->nr);
-       kfree(ca->counts);
+       if (ca->counts) {
+               memcpy(counts, ca->counts, sizeof(*counts) * ca->nr);
+               ca_destroy(ca);
+       }
        ca->nr = nr_blocks;
        ca->nr_free += extra_blocks;
        ca->counts = counts;
@@ -151,11 +164,6 @@ static int ca_commit(struct count_array *old, struct count_array *new)
        return 0;
 }
 
-static void ca_destroy(struct count_array *ca)
-{
-       kfree(ca->counts);
-}
-
 /*----------------------------------------------------------------*/
 
 struct sm_checker {
@@ -343,25 +351,25 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
        int r;
        struct sm_checker *smc;
 
-       if (!sm)
-               return NULL;
+       if (IS_ERR_OR_NULL(sm))
+               return ERR_PTR(-EINVAL);
 
        smc = kmalloc(sizeof(*smc), GFP_KERNEL);
        if (!smc)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        memcpy(&smc->sm, &ops_, sizeof(smc->sm));
        r = ca_create(&smc->old_counts, sm);
        if (r) {
                kfree(smc);
-               return NULL;
+               return ERR_PTR(r);
        }
 
        r = ca_create(&smc->counts, sm);
        if (r) {
                ca_destroy(&smc->old_counts);
                kfree(smc);
-               return NULL;
+               return ERR_PTR(r);
        }
 
        smc->real_sm = sm;
@@ -371,7 +379,7 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
                ca_destroy(&smc->counts);
                ca_destroy(&smc->old_counts);
                kfree(smc);
-               return NULL;
+               return ERR_PTR(r);
        }
 
        r = ca_commit(&smc->old_counts, &smc->counts);
@@ -379,7 +387,7 @@ struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
                ca_destroy(&smc->counts);
                ca_destroy(&smc->old_counts);
                kfree(smc);
-               return NULL;
+               return ERR_PTR(r);
        }
 
        return &smc->sm;
@@ -391,25 +399,25 @@ struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm)
        int r;
        struct sm_checker *smc;
 
-       if (!sm)
-               return NULL;
+       if (IS_ERR_OR_NULL(sm))
+               return ERR_PTR(-EINVAL);
 
        smc = kmalloc(sizeof(*smc), GFP_KERNEL);
        if (!smc)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        memcpy(&smc->sm, &ops_, sizeof(smc->sm));
        r = ca_create(&smc->old_counts, sm);
        if (r) {
                kfree(smc);
-               return NULL;
+               return ERR_PTR(r);
        }
 
        r = ca_create(&smc->counts, sm);
        if (r) {
                ca_destroy(&smc->old_counts);
                kfree(smc);
-               return NULL;
+               return ERR_PTR(r);
        }
 
        smc->real_sm = sm;
index fc469ba9f6277a7c701615a1b3d788a05fa52559..3d0ed53328831627ab6ec79cb85946f36b0fe7a4 100644 (file)
@@ -290,7 +290,16 @@ struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm,
                                       dm_block_t nr_blocks)
 {
        struct dm_space_map *sm = dm_sm_disk_create_real(tm, nr_blocks);
-       return dm_sm_checker_create_fresh(sm);
+       struct dm_space_map *smc;
+
+       if (IS_ERR_OR_NULL(sm))
+               return sm;
+
+       smc = dm_sm_checker_create_fresh(sm);
+       if (IS_ERR(smc))
+               dm_sm_destroy(sm);
+
+       return smc;
 }
 EXPORT_SYMBOL_GPL(dm_sm_disk_create);
 
index 400fe144c0cd1c94dd5c325c5ed690a425b7ece3..e5604b32d91ff0017a5a625cfd8106fca92bfe19 100644 (file)
@@ -138,6 +138,9 @@ EXPORT_SYMBOL_GPL(dm_tm_create_non_blocking_clone);
 
 void dm_tm_destroy(struct dm_transaction_manager *tm)
 {
+       if (!tm->is_clone)
+               wipe_shadow_table(tm);
+
        kfree(tm);
 }
 EXPORT_SYMBOL_GPL(dm_tm_destroy);
@@ -344,8 +347,10 @@ static int dm_tm_create_internal(struct dm_block_manager *bm,
                }
 
                *sm = dm_sm_checker_create(inner);
-               if (!*sm)
+               if (IS_ERR(*sm)) {
+                       r = PTR_ERR(*sm);
                        goto bad2;
+               }
 
        } else {
                r = dm_bm_write_lock(dm_tm_get_bm(*tm), sb_location,
@@ -364,8 +369,10 @@ static int dm_tm_create_internal(struct dm_block_manager *bm,
                }
 
                *sm = dm_sm_checker_create(inner);
-               if (!*sm)
+               if (IS_ERR(*sm)) {
+                       r = PTR_ERR(*sm);
                        goto bad2;
+               }
        }
 
        return 0;
index a9c7981ddd245c6955cbed390b617a9172abde31..cacd008d68644428914b39822417209cd00dddc8 100644 (file)
@@ -517,8 +517,8 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
                int bad_sectors;
 
                int disk = start_disk + i;
-               if (disk >= conf->raid_disks)
-                       disk -= conf->raid_disks;
+               if (disk >= conf->raid_disks * 2)
+                       disk -= conf->raid_disks * 2;
 
                rdev = rcu_dereference(conf->mirrors[disk].rdev);
                if (r1_bio->bios[disk] == IO_BLOCKED
@@ -883,7 +883,6 @@ static void make_request(struct mddev *mddev, struct bio * bio)
        const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
        const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
        struct md_rdev *blocked_rdev;
-       int plugged;
        int first_clone;
        int sectors_handled;
        int max_sectors;
@@ -1034,7 +1033,6 @@ read_again:
         * the bad blocks.  Each set of writes gets it's own r1bio
         * with a set of bios attached.
         */
-       plugged = mddev_check_plugged(mddev);
 
        disks = conf->raid_disks * 2;
  retry_write:
@@ -1191,6 +1189,8 @@ read_again:
                bio_list_add(&conf->pending_bio_list, mbio);
                conf->pending_count++;
                spin_unlock_irqrestore(&conf->device_lock, flags);
+               if (!mddev_check_plugged(mddev))
+                       md_wakeup_thread(mddev->thread);
        }
        /* Mustn't call r1_bio_write_done before this next test,
         * as it could result in the bio being freed.
@@ -1213,9 +1213,6 @@ read_again:
 
        /* In case raid1d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
-
-       if (do_sync || !bitmap || !plugged)
-               md_wakeup_thread(mddev->thread);
 }
 
 static void status(struct seq_file *seq, struct mddev *mddev)
@@ -1821,8 +1818,14 @@ static void sync_request_write(struct mddev *mddev, struct r1bio *r1_bio)
 
        if (atomic_dec_and_test(&r1_bio->remaining)) {
                /* if we're here, all write(s) have completed, so clean up */
-               md_done_sync(mddev, r1_bio->sectors, 1);
-               put_buf(r1_bio);
+               int s = r1_bio->sectors;
+               if (test_bit(R1BIO_MadeGood, &r1_bio->state) ||
+                   test_bit(R1BIO_WriteError, &r1_bio->state))
+                       reschedule_retry(r1_bio);
+               else {
+                       put_buf(r1_bio);
+                       md_done_sync(mddev, s, 1);
+               }
        }
 }
 
@@ -2488,9 +2491,10 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp
         */
        if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
                atomic_set(&r1_bio->remaining, read_targets);
-               for (i = 0; i < conf->raid_disks * 2; i++) {
+               for (i = 0; i < conf->raid_disks * 2 && read_targets; i++) {
                        bio = r1_bio->bios[i];
                        if (bio->bi_end_io == end_sync_read) {
+                               read_targets--;
                                md_sync_acct(bio->bi_bdev, nr_sectors);
                                generic_make_request(bio);
                        }
@@ -2621,7 +2625,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
                goto abort;
        }
        err = -ENOMEM;
-       conf->thread = md_register_thread(raid1d, mddev, NULL);
+       conf->thread = md_register_thread(raid1d, mddev, "raid1");
        if (!conf->thread) {
                printk(KERN_ERR
                       "md/raid1:%s: couldn't allocate thread\n",
index 99ae6068e456992ef2b16c98e01d5c2ee0362128..8da6282254c3e822a27702c469b9afce720bda43 100644 (file)
@@ -1039,7 +1039,6 @@ static void make_request(struct mddev *mddev, struct bio * bio)
        const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
        unsigned long flags;
        struct md_rdev *blocked_rdev;
-       int plugged;
        int sectors_handled;
        int max_sectors;
        int sectors;
@@ -1239,7 +1238,6 @@ read_again:
         * of r10_bios is recored in bio->bi_phys_segments just as with
         * the read case.
         */
-       plugged = mddev_check_plugged(mddev);
 
        r10_bio->read_slot = -1; /* make sure repl_bio gets freed */
        raid10_find_phys(conf, r10_bio);
@@ -1396,6 +1394,8 @@ retry_write:
                bio_list_add(&conf->pending_bio_list, mbio);
                conf->pending_count++;
                spin_unlock_irqrestore(&conf->device_lock, flags);
+               if (!mddev_check_plugged(mddev))
+                       md_wakeup_thread(mddev->thread);
 
                if (!r10_bio->devs[i].repl_bio)
                        continue;
@@ -1423,6 +1423,8 @@ retry_write:
                bio_list_add(&conf->pending_bio_list, mbio);
                conf->pending_count++;
                spin_unlock_irqrestore(&conf->device_lock, flags);
+               if (!mddev_check_plugged(mddev))
+                       md_wakeup_thread(mddev->thread);
        }
 
        /* Don't remove the bias on 'remaining' (one_write_done) until
@@ -1448,9 +1450,6 @@ retry_write:
 
        /* In case raid10d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
-
-       if (do_sync || !mddev->bitmap || !plugged)
-               md_wakeup_thread(mddev->thread);
 }
 
 static void status(struct seq_file *seq, struct mddev *mddev)
@@ -2310,7 +2309,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        if (r10_sync_page_io(rdev,
                                             r10_bio->devs[sl].addr +
                                             sect,
-                                            s<<9, conf->tmppage, WRITE)
+                                            s, conf->tmppage, WRITE)
                            == 0) {
                                /* Well, this device is dead */
                                printk(KERN_NOTICE
@@ -2349,7 +2348,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
                        switch (r10_sync_page_io(rdev,
                                             r10_bio->devs[sl].addr +
                                             sect,
-                                            s<<9, conf->tmppage,
+                                            s, conf->tmppage,
                                                 READ)) {
                        case 0:
                                /* Well, this device is dead */
@@ -2512,7 +2511,7 @@ read_more:
        slot = r10_bio->read_slot;
        printk_ratelimited(
                KERN_ERR
-               "md/raid10:%s: %s: redirecting"
+               "md/raid10:%s: %s: redirecting "
                "sector %llu to another mirror\n",
                mdname(mddev),
                bdevname(rdev->bdev, b),
@@ -2661,7 +2660,8 @@ static void raid10d(struct mddev *mddev)
        blk_start_plug(&plug);
        for (;;) {
 
-               flush_pending_writes(conf);
+               if (atomic_read(&mddev->plug_cnt) == 0)
+                       flush_pending_writes(conf);
 
                spin_lock_irqsave(&conf->device_lock, flags);
                if (list_empty(head)) {
@@ -2890,6 +2890,12 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                        /* want to reconstruct this device */
                        rb2 = r10_bio;
                        sect = raid10_find_virt(conf, sector_nr, i);
+                       if (sect >= mddev->resync_max_sectors) {
+                               /* last stripe is not complete - don't
+                                * try to recover this sector.
+                                */
+                               continue;
+                       }
                        /* Unless we are doing a full sync, or a replacement
                         * we only need to recover the block if it is set in
                         * the bitmap
@@ -3421,7 +3427,7 @@ static struct r10conf *setup_conf(struct mddev *mddev)
        spin_lock_init(&conf->resync_lock);
        init_waitqueue_head(&conf->wait_barrier);
 
-       conf->thread = md_register_thread(raid10d, mddev, NULL);
+       conf->thread = md_register_thread(raid10d, mddev, "raid10");
        if (!conf->thread)
                goto out;
 
index d26767246d26ad1d2bb9a2da371ab1bbbdf130fc..04348d76bb30fa8831964ea980ec2df912a45f92 100644 (file)
@@ -196,12 +196,14 @@ static void __release_stripe(struct r5conf *conf, struct stripe_head *sh)
                BUG_ON(!list_empty(&sh->lru));
                BUG_ON(atomic_read(&conf->active_stripes)==0);
                if (test_bit(STRIPE_HANDLE, &sh->state)) {
-                       if (test_bit(STRIPE_DELAYED, &sh->state))
+                       if (test_bit(STRIPE_DELAYED, &sh->state) &&
+                           !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
                                list_add_tail(&sh->lru, &conf->delayed_list);
                        else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
                                   sh->bm_seq - conf->seq_write > 0)
                                list_add_tail(&sh->lru, &conf->bitmap_list);
                        else {
+                               clear_bit(STRIPE_DELAYED, &sh->state);
                                clear_bit(STRIPE_BIT_DELAY, &sh->state);
                                list_add_tail(&sh->lru, &conf->handle_list);
                        }
@@ -606,6 +608,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                                         * a chance*/
                                        md_check_recovery(conf->mddev);
                                }
+                               /*
+                                * Because md_wait_for_blocked_rdev
+                                * will dec nr_pending, we must
+                                * increment it first.
+                                */
+                               atomic_inc(&rdev->nr_pending);
                                md_wait_for_blocked_rdev(rdev, conf->mddev);
                        } else {
                                /* Acknowledged bad block - skip the write */
@@ -1737,6 +1745,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
        } else {
                const char *bdn = bdevname(rdev->bdev, b);
                int retry = 0;
+               int set_bad = 0;
 
                clear_bit(R5_UPTODATE, &sh->dev[i].flags);
                atomic_inc(&rdev->read_errors);
@@ -1748,7 +1757,8 @@ static void raid5_end_read_request(struct bio * bi, int error)
                                mdname(conf->mddev),
                                (unsigned long long)s,
                                bdn);
-               else if (conf->mddev->degraded >= conf->max_degraded)
+               else if (conf->mddev->degraded >= conf->max_degraded) {
+                       set_bad = 1;
                        printk_ratelimited(
                                KERN_WARNING
                                "md/raid:%s: read error not correctable "
@@ -1756,8 +1766,9 @@ static void raid5_end_read_request(struct bio * bi, int error)
                                mdname(conf->mddev),
                                (unsigned long long)s,
                                bdn);
-               else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
+               } else if (test_bit(R5_ReWrite, &sh->dev[i].flags)) {
                        /* Oh, no!!! */
+                       set_bad = 1;
                        printk_ratelimited(
                                KERN_WARNING
                                "md/raid:%s: read error NOT corrected!! "
@@ -1765,7 +1776,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
                                mdname(conf->mddev),
                                (unsigned long long)s,
                                bdn);
-               else if (atomic_read(&rdev->read_errors)
+               else if (atomic_read(&rdev->read_errors)
                         > conf->max_nr_stripes)
                        printk(KERN_WARNING
                               "md/raid:%s: Too many read errors, failing device %s.\n",
@@ -1777,7 +1788,11 @@ static void raid5_end_read_request(struct bio * bi, int error)
                else {
                        clear_bit(R5_ReadError, &sh->dev[i].flags);
                        clear_bit(R5_ReWrite, &sh->dev[i].flags);
-                       md_error(conf->mddev, rdev);
+                       if (!(set_bad
+                             && test_bit(In_sync, &rdev->flags)
+                             && rdev_set_badblocks(
+                                     rdev, sh->sector, STRIPE_SECTORS, 0)))
+                               md_error(conf->mddev, rdev);
                }
        }
        rdev_dec_pending(rdev, conf->mddev);
@@ -3582,8 +3597,18 @@ static void handle_stripe(struct stripe_head *sh)
 
 finish:
        /* wait for this device to become unblocked */
-       if (conf->mddev->external && unlikely(s.blocked_rdev))
-               md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev);
+       if (unlikely(s.blocked_rdev)) {
+               if (conf->mddev->external)
+                       md_wait_for_blocked_rdev(s.blocked_rdev,
+                                                conf->mddev);
+               else
+                       /* Internal metadata will immediately
+                        * be written by raid5d, so we don't
+                        * need to wait here.
+                        */
+                       rdev_dec_pending(s.blocked_rdev,
+                                        conf->mddev);
+       }
 
        if (s.handle_bad_blocks)
                for (i = disks; i--; ) {
@@ -3881,8 +3906,6 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
                raid_bio->bi_next = (void*)rdev;
                align_bi->bi_bdev =  rdev->bdev;
                align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
-               /* No reshape active, so we can trust rdev->data_offset */
-               align_bi->bi_sector += rdev->data_offset;
 
                if (!bio_fits_rdev(align_bi) ||
                    is_badblock(rdev, align_bi->bi_sector, align_bi->bi_size>>9,
@@ -3893,6 +3916,9 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
                        return 0;
                }
 
+               /* No reshape active, so we can trust rdev->data_offset */
+               align_bi->bi_sector += rdev->data_offset;
+
                spin_lock_irq(&conf->device_lock);
                wait_event_lock_irq(conf->wait_for_stripe,
                                    conf->quiesce == 0,
@@ -3971,7 +3997,6 @@ static void make_request(struct mddev *mddev, struct bio * bi)
        struct stripe_head *sh;
        const int rw = bio_data_dir(bi);
        int remaining;
-       int plugged;
 
        if (unlikely(bi->bi_rw & REQ_FLUSH)) {
                md_flush_request(mddev, bi);
@@ -3990,7 +4015,6 @@ static void make_request(struct mddev *mddev, struct bio * bi)
        bi->bi_next = NULL;
        bi->bi_phys_segments = 1;       /* over-loaded to count active stripes */
 
-       plugged = mddev_check_plugged(mddev);
        for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
                DEFINE_WAIT(w);
                int previous;
@@ -4092,6 +4116,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                        if ((bi->bi_rw & REQ_SYNC) &&
                            !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
                                atomic_inc(&conf->preread_active_stripes);
+                       mddev_check_plugged(mddev);
                        release_stripe(sh);
                } else {
                        /* cannot get stripe for read-ahead, just give-up */
@@ -4099,10 +4124,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                        finish_wait(&conf->wait_for_overlap, &w);
                        break;
                }
-                       
        }
-       if (!plugged)
-               md_wakeup_thread(mddev->thread);
 
        spin_lock_irq(&conf->device_lock);
        remaining = raid5_dec_bi_phys_segments(bi);
@@ -4823,6 +4845,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
        int raid_disk, memory, max_disks;
        struct md_rdev *rdev;
        struct disk_info *disk;
+       char pers_name[6];
 
        if (mddev->new_level != 5
            && mddev->new_level != 4
@@ -4946,7 +4969,8 @@ static struct r5conf *setup_conf(struct mddev *mddev)
                printk(KERN_INFO "md/raid:%s: allocated %dkB\n",
                       mdname(mddev), memory);
 
-       conf->thread = md_register_thread(raid5d, mddev, NULL);
+       sprintf(pers_name, "raid%d", mddev->new_level);
+       conf->thread = md_register_thread(raid5d, mddev, pers_name);
        if (!conf->thread) {
                printk(KERN_ERR
                       "md/raid:%s: couldn't allocate thread.\n",
@@ -5465,10 +5489,9 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
        if (rdev->saved_raid_disk >= 0 &&
            rdev->saved_raid_disk >= first &&
            conf->disks[rdev->saved_raid_disk].rdev == NULL)
-               disk = rdev->saved_raid_disk;
-       else
-               disk = first;
-       for ( ; disk <= last ; disk++) {
+               first = rdev->saved_raid_disk;
+
+       for (disk = first; disk <= last; disk++) {
                p = conf->disks + disk;
                if (p->rdev == NULL) {
                        clear_bit(In_sync, &rdev->flags);
@@ -5477,8 +5500,11 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                        if (rdev->saved_raid_disk != disk)
                                conf->fullsync = 1;
                        rcu_assign_pointer(p->rdev, rdev);
-                       break;
+                       goto out;
                }
+       }
+       for (disk = first; disk <= last; disk++) {
+               p = conf->disks + disk;
                if (test_bit(WantReplacement, &p->rdev->flags) &&
                    p->replacement == NULL) {
                        clear_bit(In_sync, &rdev->flags);
@@ -5490,6 +5516,7 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                        break;
                }
        }
+out:
        print_raid5_conf(conf);
        return err;
 }
index 00a67326c1931dd01496a1fdb8544ae0ceb77206..39eab73b01ae9bb5e0a9c4d9667e3c99b4b51415 100644 (file)
@@ -243,6 +243,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        if (minor == MAX_DVB_MINORS) {
                kfree(dvbdevfops);
                kfree(dvbdev);
+               up_write(&minor_rwsem);
                mutex_unlock(&dvbdev_register_lock);
                return -EINVAL;
        }
index 342c2c8c1ddfcff71f493f3f6f08a4f1969df440..54ee34872d143cea7345f60a5ad9038e91266a51 100644 (file)
@@ -232,7 +232,7 @@ MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
 
 static bool txandrx; /* default = 0 */
 module_param(txandrx, bool, 0444);
-MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX");
+MODULE_PARM_DESC(txandrx, "Allow simultaneous TX and RX");
 
 static unsigned int wake_sc = 0x800F040C;
 module_param(wake_sc, uint, 0644);
@@ -1032,6 +1032,8 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
        data->dev->tx_ir = wbcir_tx;
        data->dev->priv = data;
        data->dev->dev.parent = &device->dev;
+       data->dev->timeout = MS_TO_NS(100);
+       data->dev->allowed_protos = RC_TYPE_ALL;
 
        if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) {
                dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
index 068f78dc5d13fa0268eef854b4956d18f7521bba..b4c99c7270cf8fc8d28d26226248208f8b930dad 100644 (file)
@@ -307,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
                urb->context = dev;
                urb->pipe = usb_rcvisocpipe(dev->udev,
                                                dev->adev.end_point_addr);
-               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_flags = URB_ISO_ASAP;
                urb->transfer_buffer = dev->adev.transfer_buffer[i];
                urb->interval = 1;
                urb->complete = cx231xx_audio_isocirq;
@@ -368,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
                urb->context = dev;
                urb->pipe = usb_rcvbulkpipe(dev->udev,
                                                dev->adev.end_point_addr);
-               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_flags = 0;
                urb->transfer_buffer = dev->adev.transfer_buffer[i];
                urb->complete = cx231xx_audio_bulkirq;
                urb->transfer_buffer_length = sb_size;
index 3d15314e1f88d1ff71924a7a65362dd13b75fd12..ac7db52f404ffbc9c95207f7a2bd5b1414aa4187 100644 (file)
@@ -448,7 +448,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
                        return -ENOMEM;
                }
                dev->vbi_mode.bulk_ctl.urb[i] = urb;
-               urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_flags = 0;
 
                dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
                    kzalloc(sb_size, GFP_KERNEL);
index 13739e002a63fb6460bec16572bad10581fcb998..080e11157e5fe89afdb384c702376d80528daf5d 100644 (file)
@@ -127,22 +127,37 @@ struct cx23885_board cx23885_boards[] = {
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1250] = {
                .name           = "Hauppauge WinTV-HVR1250",
+               .porta          = CX23885_ANALOG_VIDEO,
                .portc          = CX23885_MPEG_DVB,
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
+               .tuner_type     = TUNER_PHILIPS_TDA8290,
+               .tuner_addr     = 0x42, /* 0x84 >> 1 */
+               .tuner_bus      = 1,
+#endif
+               .force_bff      = 1,
                .input          = {{
+#ifdef MT2131_NO_ANALOG_SUPPORT_YET
                        .type   = CX23885_VMUX_TELEVISION,
-                       .vmux   = 0,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN5_CH2 |
+                                       CX25840_VIN2_CH1,
+                       .amux   = CX25840_AUDIO8,
                        .gpio0  = 0xff00,
                }, {
-                       .type   = CX23885_VMUX_DEBUG,
-                       .vmux   = 0,
-                       .gpio0  = 0xff01,
-               }, {
+#endif
                        .type   = CX23885_VMUX_COMPOSITE1,
-                       .vmux   = 1,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN6_CH1,
+                       .amux   = CX25840_AUDIO7,
                        .gpio0  = 0xff02,
                }, {
                        .type   = CX23885_VMUX_SVIDEO,
-                       .vmux   = 2,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN8_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .amux   = CX25840_AUDIO7,
                        .gpio0  = 0xff02,
                } },
        },
@@ -267,7 +282,55 @@ struct cx23885_board cx23885_boards[] = {
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1255] = {
                .name           = "Hauppauge WinTV-HVR1255",
+               .porta          = CX23885_ANALOG_VIDEO,
+               .portc          = CX23885_MPEG_DVB,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = 0x42, /* 0x84 >> 1 */
+               .force_bff      = 1,
+               .input          = {{
+                       .type   = CX23885_VMUX_TELEVISION,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN5_CH2 |
+                                       CX25840_VIN2_CH1 |
+                                       CX25840_DIF_ON,
+                       .amux   = CX25840_AUDIO8,
+               }, {
+                       .type   = CX23885_VMUX_COMPOSITE1,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN6_CH1,
+                       .amux   = CX25840_AUDIO7,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN8_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .amux   = CX25840_AUDIO7,
+               } },
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1255_22111] = {
+               .name           = "Hauppauge WinTV-HVR1255",
+               .porta          = CX23885_ANALOG_VIDEO,
                .portc          = CX23885_MPEG_DVB,
+               .tuner_type     = TUNER_ABSENT,
+               .tuner_addr     = 0x42, /* 0x84 >> 1 */
+               .force_bff      = 1,
+               .input          = {{
+                       .type   = CX23885_VMUX_TELEVISION,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN5_CH2 |
+                                       CX25840_VIN2_CH1 |
+                                       CX25840_DIF_ON,
+                       .amux   = CX25840_AUDIO8,
+               }, {
+                       .type   = CX23885_VMUX_SVIDEO,
+                       .vmux   =       CX25840_VIN7_CH3 |
+                                       CX25840_VIN4_CH2 |
+                                       CX25840_VIN8_CH1 |
+                                       CX25840_SVIDEO_ON,
+                       .amux   = CX25840_AUDIO7,
+               } },
        },
        [CX23885_BOARD_HAUPPAUGE_HVR1210] = {
                .name           = "Hauppauge WinTV-HVR1210",
@@ -624,7 +687,7 @@ struct cx23885_subid cx23885_subids[] = {
        }, {
                .subvendor = 0x0070,
                .subdevice = 0x2259,
-               .card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1255_22111,
        }, {
                .subvendor = 0x0070,
                .subdevice = 0x2291,
@@ -900,7 +963,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
        struct cx23885_dev *dev = port->dev;
        u32 bitmask = 0;
 
-       if (command == XC2028_RESET_CLK)
+       if ((command == XC2028_RESET_CLK) || (command == XC2028_I2C_FLUSH))
                return 0;
 
        if (command != 0) {
@@ -1130,6 +1193,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
                /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */
                /* GPIO-6 I2C Gate which can isolate the demod from the bus */
@@ -1267,6 +1331,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
                /* FIXME: Implement me */
                break;
@@ -1424,6 +1489,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
@@ -1511,6 +1577,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1275:
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
        case CX23885_BOARD_HAUPPAUGE_HVR1210:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
@@ -1526,10 +1593,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
         */
        switch (dev->board) {
        case CX23885_BOARD_TEVII_S470:
-       case CX23885_BOARD_HAUPPAUGE_HVR1250:
                /* Currently only enabled for the integrated IR controller */
                if (!enable_885_ir)
                        break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
@@ -1539,6 +1606,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
        case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_MYGICA_X8506:
index a80a92c474558a4c555a473c89aa1df568c88288..cd542684ba022c4f194928e37cfc318d6a1b0b79 100644 (file)
@@ -712,6 +712,7 @@ static int dvb_register(struct cx23885_tsport *port)
                }
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
                i2c_bus = &dev->i2c_bus[0];
                fe0->dvb.frontend = dvb_attach(s5h1411_attach,
                                               &hcw_s5h1411_config,
@@ -721,6 +722,11 @@ static int dvb_register(struct cx23885_tsport *port)
                                   0x60, &dev->i2c_bus[1].i2c_adap,
                                   &hauppauge_tda18271_config);
                }
+
+               tda18271_attach(&dev->ts1.analog_fe,
+                       0x60, &dev->i2c_bus[1].i2c_adap,
+                       &hauppauge_tda18271_config);
+
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
                i2c_bus = &dev->i2c_bus[0];
index c654bdc7ccb201dd4e285c0b7ddfe703ab89cb61..22f8e7fbd6656fe81f33f824832a38cc7e2dd14c 100644 (file)
@@ -505,6 +505,9 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
 
        if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) ||
                (dev->board == CX23885_BOARD_MPX885) ||
+               (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) ||
+               (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+               (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
                (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) {
                /* Configure audio routing */
                v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
@@ -1578,7 +1581,9 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
 
        fe = vfe->dvb.frontend;
 
-       if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)
+       if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
+           (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+           (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111))
                fe = &dev->ts1.analog_fe;
 
        if (fe && fe->ops.tuner_ops.set_analog_params) {
@@ -1608,6 +1613,8 @@ int cx23885_set_frequency(struct file *file, void *priv,
        int ret;
 
        switch (dev->board) {
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
                ret = cx23885_set_freq_via_ops(dev, f);
                break;
index d884784a1c8582f8a97c379dacc5ef603d2f934c..13c37ec07ae7e250b54694aad7c821c670fd584f 100644 (file)
@@ -90,6 +90,7 @@
 #define CX23885_BOARD_MYGICA_X8507             33
 #define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
 #define CX23885_BOARD_TEVII_S471               35
+#define CX23885_BOARD_HAUPPAUGE_HVR1255_22111  36
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
index 83c1aa6b2e6c9a8762065e4c5994c62f033f3fba..f11f6f07e9154cd4d00790031d3da5e63c1ec8d1 100644 (file)
@@ -904,9 +904,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
        list_add_tail(&dev->devlist, &cx25821_devlist);
        mutex_unlock(&cx25821_devlist_mutex);
 
-       strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown");
-       strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821");
-
        if (dev->pci->device != 0x8210) {
                pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
                        __func__, dev->pci->device);
index b9aa801b00a7b29c01c45334dd14d6c7c61bb978..029f2934a6d88bccdb409becdfd17849b99dff3b 100644 (file)
@@ -187,7 +187,7 @@ enum port {
 };
 
 struct cx25821_board {
-       char *name;
+       const char *name;
        enum port porta;
        enum port portb;
        enum port portc;
index fc1ff69cffd0d4917e86292573691be2436282fc..d8eac3e30a7ea99217e5b149de79752e73f594cf 100644 (file)
@@ -84,7 +84,7 @@ MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
 
 
 /* ----------------------------------------------------------------------- */
-static void cx23885_std_setup(struct i2c_client *client);
+static void cx23888_std_setup(struct i2c_client *client);
 
 int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
 {
@@ -638,10 +638,13 @@ static void cx23885_initialize(struct i2c_client *client)
        finish_wait(&state->fw_wait, &wait);
        destroy_workqueue(q);
 
-       /* Call the cx23885 specific std setup func, we no longer rely on
+       /* Call the cx23888 specific std setup func, we no longer rely on
         * the generic cx24840 func.
         */
-       cx23885_std_setup(client);
+       if (is_cx23888(state))
+               cx23888_std_setup(client);
+       else
+               cx25840_std_setup(client);
 
        /* (re)set input */
        set_input(client, state->vid_input, state->aud_input);
@@ -1103,9 +1106,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 
                        cx25840_write4(client, 0x410, 0xffff0dbf);
                        cx25840_write4(client, 0x414, 0x00137d03);
-                       cx25840_write4(client, 0x418, 0x01008080);
+
+                       /* on the 887, 0x418 is HSCALE_CTRL, on the 888 it is 
+                          CHROMA_CTRL */
+                       if (is_cx23888(state))
+                               cx25840_write4(client, 0x418, 0x01008080);
+                       else
+                               cx25840_write4(client, 0x418, 0x01000000);
+
                        cx25840_write4(client, 0x41c, 0x00000000);
-                       cx25840_write4(client, 0x420, 0x001c3e0f);
+
+                       /* on the 887, 0x420 is CHROMA_CTRL, on the 888 it is 
+                          CRUSH_CTRL */
+                       if (is_cx23888(state))
+                               cx25840_write4(client, 0x420, 0x001c3e0f);
+                       else
+                               cx25840_write4(client, 0x420, 0x001c8282);
+
                        cx25840_write4(client, 0x42c, 0x42600000);
                        cx25840_write4(client, 0x430, 0x0000039b);
                        cx25840_write4(client, 0x438, 0x00000000);
@@ -1233,7 +1250,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
                cx25840_write4(client, 0x8d0, 0x1f063870);
        }
 
-       if (is_cx2388x(state)) {
+       if (is_cx23888(state)) {
                /* HVR1850 */
                /* AUD_IO_CTRL - I2S Input, Parallel1*/
                /*  - Channel 1 src - Parallel1 (Merlin out) */
@@ -1298,8 +1315,8 @@ static int set_v4lstd(struct i2c_client *client)
        }
        cx25840_and_or(client, 0x400, ~0xf, fmt);
        cx25840_and_or(client, 0x403, ~0x3, pal_m);
-       if (is_cx2388x(state))
-               cx23885_std_setup(client);
+       if (is_cx23888(state))
+               cx23888_std_setup(client);
        else
                cx25840_std_setup(client);
        if (!is_cx2583x(state))
@@ -1312,6 +1329,7 @@ static int set_v4lstd(struct i2c_client *client)
 static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
+       struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        switch (ctrl->id) {
@@ -1324,12 +1342,20 @@ static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
 
        case V4L2_CID_SATURATION:
-               cx25840_write(client, 0x420, ctrl->val << 1);
-               cx25840_write(client, 0x421, ctrl->val << 1);
+               if (is_cx23888(state)) {
+                       cx25840_write(client, 0x418, ctrl->val << 1);
+                       cx25840_write(client, 0x419, ctrl->val << 1);
+               } else {
+                       cx25840_write(client, 0x420, ctrl->val << 1);
+                       cx25840_write(client, 0x421, ctrl->val << 1);
+               }
                break;
 
        case V4L2_CID_HUE:
-               cx25840_write(client, 0x422, ctrl->val);
+               if (is_cx23888(state))
+                       cx25840_write(client, 0x41a, ctrl->val);
+               else
+                       cx25840_write(client, 0x422, ctrl->val);
                break;
 
        default:
@@ -1354,11 +1380,21 @@ static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
        fmt->field = V4L2_FIELD_INTERLACED;
        fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
 
-       Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
-       Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+       if (is_cx23888(state)) {
+               Vsrc = (cx25840_read(client, 0x42a) & 0x3f) << 4;
+               Vsrc |= (cx25840_read(client, 0x429) & 0xf0) >> 4;
+       } else {
+               Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+               Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+       }
 
-       Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
-       Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+       if (is_cx23888(state)) {
+               Hsrc = (cx25840_read(client, 0x426) & 0x3f) << 4;
+               Hsrc |= (cx25840_read(client, 0x425) & 0xf0) >> 4;
+       } else {
+               Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+               Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+       }
 
        Vlines = fmt->height + (is_50Hz ? 4 : 7);
 
@@ -1782,8 +1818,8 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd,
        struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (is_cx2388x(state))
-               cx23885_std_setup(client);
+       if (is_cx23888(state))
+               cx23888_std_setup(client);
 
        return set_input(client, input, state->aud_input);
 }
@@ -1794,8 +1830,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
        struct cx25840_state *state = to_state(sd);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       if (is_cx2388x(state))
-               cx23885_std_setup(client);
+       if (is_cx23888(state))
+               cx23888_std_setup(client);
        return set_input(client, state->vid_input, input);
 }
 
@@ -4939,7 +4975,7 @@ void cx23885_dif_setup(struct i2c_client *client, u32 ifHz)
        }
 }
 
-static void cx23885_std_setup(struct i2c_client *client)
+static void cx23888_std_setup(struct i2c_client *client)
 {
        struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        v4l2_std_id std = state->std;
index 92da7c28b6f096f9f7c37a79aef39cdd126aae5a..862c6575c55791fa7a6f4488d7cd933226fd02cb 100644 (file)
@@ -2893,7 +2893,7 @@ static void request_module_async(struct work_struct *work)
 
        if (dev->board.has_dvb)
                request_module("em28xx-dvb");
-       if (dev->board.has_ir_i2c && !disable_ir)
+       if (dev->board.ir_codes && !disable_ir)
                request_module("em28xx-rc");
 }
 
index 6c31e46a1fd2ed4356b829abf916fee6e215b63e..b9c6f17eabb245fde118e3b198f163782d92a7bc 100644 (file)
@@ -2070,10 +2070,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
        set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
        set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
                        v4l2_ctrl_g_ctrl(sd->red));
-       set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
-       set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
-       set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
-                       v4l2_ctrl_g_ctrl(sd->vflip));
+       if (sd->gain)
+               set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
+       if (sd->exposure)
+               set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
+       if (sd->hflip)
+               set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
+                               v4l2_ctrl_g_ctrl(sd->vflip));
 
        reg_w1(gspca_dev, 0x1007, 0x20);
        reg_w1(gspca_dev, 0x1061, 0x03);
@@ -2176,7 +2179,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int avg_lum;
 
-       if (!v4l2_ctrl_g_ctrl(sd->autogain))
+       if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
                return;
 
        avg_lum = atomic_read(&sd->avg_lum);
index 41f9a254b24590a572223c35909255017e392612..637bde8aca28e25c2799cd85aded6eedafa3075c 100644 (file)
@@ -83,6 +83,7 @@
 #define CSICR1_INV_DATA                (1 << 3)
 #define CSICR1_INV_PCLK                (1 << 2)
 #define CSICR1_REDGE           (1 << 1)
+#define CSICR1_FMT_MASK                (CSICR1_PACK_DIR | CSICR1_SWAP16_EN)
 
 #define SHIFT_STATFF_LEVEL     22
 #define SHIFT_RXFF_LEVEL       19
@@ -230,6 +231,7 @@ struct mx2_prp_cfg {
        u32 src_pixel;
        u32 ch1_pixel;
        u32 irq_flags;
+       u32 csicr1;
 };
 
 /* prp resizing parameters */
@@ -330,6 +332,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
                        .ch1_pixel      = 0x2ca00565, /* RGB565 */
                        .irq_flags      = PRP_INTR_RDERR | PRP_INTR_CH1WERR |
                                                PRP_INTR_CH1FC | PRP_INTR_LBOVF,
+                       .csicr1         = 0,
                }
        },
        {
@@ -343,6 +346,21 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
                        .irq_flags      = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
                                        PRP_INTR_CH2FC | PRP_INTR_LBOVF |
                                        PRP_INTR_CH2OVF,
+                       .csicr1         = CSICR1_PACK_DIR,
+               }
+       },
+       {
+               .in_fmt         = V4L2_MBUS_FMT_UYVY8_2X8,
+               .out_fmt        = V4L2_PIX_FMT_YUV420,
+               .cfg            = {
+                       .channel        = 2,
+                       .in_fmt         = PRP_CNTL_DATA_IN_YUV422,
+                       .out_fmt        = PRP_CNTL_CH2_OUT_YUV420,
+                       .src_pixel      = 0x22000888, /* YUV422 (YUYV) */
+                       .irq_flags      = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+                                       PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+                                       PRP_INTR_CH2OVF,
+                       .csicr1         = CSICR1_SWAP16_EN,
                }
        },
 };
@@ -1015,14 +1033,14 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
                return ret;
        }
 
+       csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1;
+
        if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
                csicr1 |= CSICR1_REDGE;
        if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
                csicr1 |= CSICR1_SOF_POL;
        if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
                csicr1 |= CSICR1_HSYNC_POL;
-       if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
-               csicr1 |= CSICR1_SWAP16_EN;
        if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
                csicr1 |= CSICR1_EXT_VSYNC;
        if (pcdev->platform_flags & MX2_CAMERA_CCIR)
@@ -1033,8 +1051,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
                csicr1 |= CSICR1_GCLK_MODE;
        if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
                csicr1 |= CSICR1_INV_DATA;
-       if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
-               csicr1 |= CSICR1_PACK_DIR;
 
        pcdev->csicr1 = csicr1;
 
@@ -1109,7 +1125,8 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
                return 0;
        }
 
-       if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
+       if (code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+           code == V4L2_MBUS_FMT_UYVY8_2X8) {
                formats++;
                if (xlate) {
                        /*
index 8a4935ecc655e9c114cd2f7defb51498f50d38c5..dd91da26f1b088f66bdb40b212fa9b1c84a46b5a 100644 (file)
@@ -888,12 +888,12 @@ static const struct preview_update update_attrs[] = {
                preview_config_contrast,
                NULL,
                offsetof(struct prev_params, contrast),
-               0, true,
+               0, 0, true,
        }, /* OMAP3ISP_PREV_BRIGHTNESS */ {
                preview_config_brightness,
                NULL,
                offsetof(struct prev_params, brightness),
-               0, true,
+               0, 0, true,
        },
 };
 
@@ -1102,7 +1102,7 @@ static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
        unsigned int elv = prev->crop.top + prev->crop.height - 1;
        u32 features;
 
-       if (format->code == V4L2_MBUS_FMT_Y10_1X10) {
+       if (format->code != V4L2_MBUS_FMT_Y10_1X10) {
                sph -= 2;
                eph += 2;
                slv -= 2;
index c370c2d87c1798594c794d744c3dbf1bb08859cd..b4c679b3fb0f7a052550a7d5a71ea42367e49ceb 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
index 354574591908ee9cbbea18a5c518e04e2b9b4839..725812aa0c3044f5ffa31190a734e75ffcc9c01b 100644 (file)
@@ -350,7 +350,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
                if (pixm)
                        sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
                else
-                       sizes[i] = size;
+                       sizes[i] = max_t(u32, size, frame->payload[i]);
+
                allocators[i] = ctx->fimc_dev->alloc_ctx;
        }
 
@@ -479,37 +480,39 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc);
 static int fimc_capture_open(struct file *file)
 {
        struct fimc_dev *fimc = video_drvdata(file);
-       int ret = v4l2_fh_open(file);
-
-       if (ret)
-               return ret;
+       int ret;
 
        dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
 
-       /* Return if the corresponding video mem2mem node is already opened. */
        if (fimc_m2m_active(fimc))
                return -EBUSY;
 
        set_bit(ST_CAPT_BUSY, &fimc->state);
-       pm_runtime_get_sync(&fimc->pdev->dev);
+       ret = pm_runtime_get_sync(&fimc->pdev->dev);
+       if (ret < 0)
+               return ret;
 
-       if (++fimc->vid_cap.refcnt == 1) {
-               ret = fimc_pipeline_initialize(&fimc->pipeline,
-                              &fimc->vid_cap.vfd->entity, true);
-               if (ret < 0) {
-                       dev_err(&fimc->pdev->dev,
-                               "Video pipeline initialization failed\n");
-                       pm_runtime_put_sync(&fimc->pdev->dev);
-                       fimc->vid_cap.refcnt--;
-                       v4l2_fh_release(file);
-                       clear_bit(ST_CAPT_BUSY, &fimc->state);
-                       return ret;
-               }
-               ret = fimc_capture_ctrls_create(fimc);
+       ret = v4l2_fh_open(file);
+       if (ret)
+               return ret;
 
-               if (!ret && !fimc->vid_cap.user_subdev_api)
-                       ret = fimc_capture_set_default_format(fimc);
+       if (++fimc->vid_cap.refcnt != 1)
+               return 0;
+
+       ret = fimc_pipeline_initialize(&fimc->pipeline,
+                                      &fimc->vid_cap.vfd->entity, true);
+       if (ret < 0) {
+               clear_bit(ST_CAPT_BUSY, &fimc->state);
+               pm_runtime_put_sync(&fimc->pdev->dev);
+               fimc->vid_cap.refcnt--;
+               v4l2_fh_release(file);
+               return ret;
        }
+       ret = fimc_capture_ctrls_create(fimc);
+
+       if (!ret && !fimc->vid_cap.user_subdev_api)
+               ret = fimc_capture_set_default_format(fimc);
+
        return ret;
 }
 
@@ -818,9 +821,6 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,
        struct fimc_dev *fimc = video_drvdata(file);
        struct fimc_ctx *ctx = fimc->vid_cap.ctx;
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-               return -EINVAL;
-
        return fimc_fill_format(&ctx->d_frame, f);
 }
 
@@ -833,9 +833,6 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
        struct v4l2_mbus_framefmt mf;
        struct fimc_fmt *ffmt = NULL;
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-               return -EINVAL;
-
        if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
                fimc_capture_try_format(ctx, &pix->width, &pix->height,
                                        NULL, &pix->pixelformat,
@@ -887,8 +884,6 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
        struct fimc_fmt *s_fmt = NULL;
        int ret, i;
 
-       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-               return -EINVAL;
        if (vb2_is_busy(&fimc->vid_cap.vbq))
                return -EBUSY;
 
@@ -924,10 +919,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
                pix->width  = mf->width;
                pix->height = mf->height;
        }
+
        fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix);
        for (i = 0; i < ff->fmt->colplanes; i++)
-               ff->payload[i] =
-                       (pix->width * pix->height * ff->fmt->depth[i]) / 8;
+               ff->payload[i] = pix->plane_fmt[i].sizeimage;
 
        set_frame_bounds(ff, pix->width, pix->height);
        /* Reset the composition rectangle if not yet configured */
@@ -1045,18 +1040,22 @@ static int fimc_cap_streamon(struct file *file, void *priv,
 {
        struct fimc_dev *fimc = video_drvdata(file);
        struct fimc_pipeline *p = &fimc->pipeline;
+       struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
        int ret;
 
        if (fimc_capture_active(fimc))
                return -EBUSY;
 
-       media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity,
-                                   p->m_pipeline);
+       ret = media_entity_pipeline_start(&sd->entity, p->m_pipeline);
+       if (ret < 0)
+               return ret;
 
        if (fimc->vid_cap.user_subdev_api) {
                ret = fimc_pipeline_validate(fimc);
-               if (ret)
+               if (ret < 0) {
+                       media_entity_pipeline_stop(&sd->entity);
                        return ret;
+               }
        }
        return vb2_streamon(&fimc->vid_cap.vbq, type);
 }
index 92fc5a20fb768c5266b9e7d7506b20c9d0de511d..a4646ca1d56f31fb30eb35d7cd9829fa5aa9f46a 100644 (file)
@@ -153,7 +153,7 @@ static struct fimc_fmt fimc_formats[] = {
                .colplanes      = 2,
                .flags          = FMT_FLAGS_M2M,
        }, {
-               .name           = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+               .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
                .fourcc         = V4L2_PIX_FMT_NV12M,
                .color          = FIMC_FMT_YCBCR420,
                .depth          = { 8, 4 },
@@ -161,7 +161,7 @@ static struct fimc_fmt fimc_formats[] = {
                .colplanes      = 2,
                .flags          = FMT_FLAGS_M2M,
        }, {
-               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+               .name           = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
                .fourcc         = V4L2_PIX_FMT_YUV420M,
                .color          = FIMC_FMT_YCBCR420,
                .depth          = { 8, 2, 2 },
@@ -169,7 +169,7 @@ static struct fimc_fmt fimc_formats[] = {
                .colplanes      = 3,
                .flags          = FMT_FLAGS_M2M,
        }, {
-               .name           = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
+               .name           = "YUV 4:2:0 non-contig. 2p, tiled",
                .fourcc         = V4L2_PIX_FMT_NV12MT,
                .color          = FIMC_FMT_YCBCR420,
                .depth          = { 8, 4 },
@@ -641,7 +641,7 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
        if (!ctrls->ready)
                return;
 
-       mutex_lock(&ctrls->handler.lock);
+       mutex_lock(ctrls->handler.lock);
        v4l2_ctrl_activate(ctrls->rotate, active);
        v4l2_ctrl_activate(ctrls->hflip, active);
        v4l2_ctrl_activate(ctrls->vflip, active);
@@ -660,7 +660,7 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
                ctx->hflip    = 0;
                ctx->vflip    = 0;
        }
-       mutex_unlock(&ctrls->handler.lock);
+       mutex_unlock(ctrls->handler.lock);
 }
 
 /* Update maximum value of the alpha color control */
@@ -741,8 +741,8 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
        pix->width = width;
 
        for (i = 0; i < pix->num_planes; ++i) {
-               u32 bpl = pix->plane_fmt[i].bytesperline;
-               u32 *sizeimage = &pix->plane_fmt[i].sizeimage;
+               struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i];
+               u32 bpl = plane_fmt->bytesperline;
 
                if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
                        bpl = pix->width; /* Planar */
@@ -754,8 +754,9 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
                if (i == 0) /* Same bytesperline for each plane. */
                        bytesperline = bpl;
 
-               pix->plane_fmt[i].bytesperline = bytesperline;
-               *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8;
+               plane_fmt->bytesperline = bytesperline;
+               plane_fmt->sizeimage = max((pix->width * pix->height *
+                                  fmt->depth[i]) / 8, plane_fmt->sizeimage);
        }
 }
 
index 400d701aef04126d8d3b469a51b7a9adb360985c..74ff310db30cd6755393b5b6eaf2a933495fa0e9 100644 (file)
@@ -451,34 +451,44 @@ static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
 static int fimc_lite_open(struct file *file)
 {
        struct fimc_lite *fimc = video_drvdata(file);
-       int ret = v4l2_fh_open(file);
+       int ret;
 
-       if (ret)
-               return ret;
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
 
        set_bit(ST_FLITE_IN_USE, &fimc->state);
-       pm_runtime_get_sync(&fimc->pdev->dev);
+       ret = pm_runtime_get_sync(&fimc->pdev->dev);
+       if (ret < 0)
+               goto done;
 
-       if (++fimc->ref_count != 1 || fimc->out_path != FIMC_IO_DMA)
-               return ret;
+       ret = v4l2_fh_open(file);
+       if (ret < 0)
+               goto done;
 
-       ret = fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity,
-                                      true);
-       if (ret < 0) {
-               v4l2_err(fimc->vfd, "Video pipeline initialization failed\n");
-               pm_runtime_put_sync(&fimc->pdev->dev);
-               fimc->ref_count--;
-               v4l2_fh_release(file);
-               clear_bit(ST_FLITE_IN_USE, &fimc->state);
-       }
+       if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) {
+               ret = fimc_pipeline_initialize(&fimc->pipeline,
+                                              &fimc->vfd->entity, true);
+               if (ret < 0) {
+                       pm_runtime_put_sync(&fimc->pdev->dev);
+                       fimc->ref_count--;
+                       v4l2_fh_release(file);
+                       clear_bit(ST_FLITE_IN_USE, &fimc->state);
+               }
 
-       fimc_lite_clear_event_counters(fimc);
+               fimc_lite_clear_event_counters(fimc);
+       }
+done:
+       mutex_unlock(&fimc->lock);
        return ret;
 }
 
 static int fimc_lite_close(struct file *file)
 {
        struct fimc_lite *fimc = video_drvdata(file);
+       int ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
 
        if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
                clear_bit(ST_FLITE_IN_USE, &fimc->state);
@@ -492,20 +502,39 @@ static int fimc_lite_close(struct file *file)
        if (fimc->ref_count == 0)
                vb2_queue_release(&fimc->vb_queue);
 
-       return v4l2_fh_release(file);
+       ret = v4l2_fh_release(file);
+
+       mutex_unlock(&fimc->lock);
+       return ret;
 }
 
 static unsigned int fimc_lite_poll(struct file *file,
                                   struct poll_table_struct *wait)
 {
        struct fimc_lite *fimc = video_drvdata(file);
-       return vb2_poll(&fimc->vb_queue, file, wait);
+       int ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return POLL_ERR;
+
+       ret = vb2_poll(&fimc->vb_queue, file, wait);
+       mutex_unlock(&fimc->lock);
+
+       return ret;
 }
 
 static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct fimc_lite *fimc = video_drvdata(file);
-       return vb2_mmap(&fimc->vb_queue, vma);
+       int ret;
+
+       if (mutex_lock_interruptible(&fimc->lock))
+               return -ERESTARTSYS;
+
+       ret = vb2_mmap(&fimc->vb_queue, vma);
+       mutex_unlock(&fimc->lock);
+
+       return ret;
 }
 
 static const struct v4l2_file_operations fimc_lite_fops = {
@@ -762,7 +791,9 @@ static int fimc_lite_streamon(struct file *file, void *priv,
        if (fimc_lite_active(fimc))
                return -EBUSY;
 
-       media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+       ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+       if (ret < 0)
+               return ret;
 
        ret = fimc_pipeline_validate(fimc);
        if (ret) {
@@ -1508,7 +1539,7 @@ static int fimc_lite_suspend(struct device *dev)
                return 0;
 
        ret = fimc_lite_stop_capture(fimc, suspend);
-       if (ret)
+       if (ret < 0 || !fimc_lite_active(fimc))
                return ret;
 
        return fimc_pipeline_shutdown(&fimc->pipeline);
index 6753c45631b856e1a06d19492e56e97edf01f9f6..52cef4865423ef2be451df098d0c2ada3412fe21 100644 (file)
@@ -193,9 +193,13 @@ int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
 
 int fimc_pipeline_shutdown(struct fimc_pipeline *p)
 {
-       struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity;
+       struct media_entity *me;
        int ret;
 
+       if (!p || !p->subdevs[IDX_SENSOR])
+               return -EINVAL;
+
+       me = &p->subdevs[IDX_SENSOR]->entity;
        mutex_lock(&me->parent->graph_mutex);
        ret = __fimc_pipeline_shutdown(p);
        mutex_unlock(&me->parent->graph_mutex);
@@ -498,12 +502,12 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
  * @source: the source entity to create links to all fimc entities from
  * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null
  * @pad: the source entity pad index
- * @fimc_id: index of the fimc device for which link should be enabled
+ * @link_mask: bitmask of the fimc devices for which link should be enabled
  */
 static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
                                            struct media_entity *source,
                                            struct v4l2_subdev *sensor,
-                                           int pad, int fimc_id)
+                                           int pad, int link_mask)
 {
        struct fimc_sensor_info *s_info;
        struct media_entity *sink;
@@ -520,7 +524,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
                if (!fmd->fimc[i]->variant->has_cam_if)
                        continue;
 
-               flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
+               flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0;
 
                sink = &fmd->fimc[i]->vid_cap.subdev.entity;
                ret = media_entity_create_link(source, pad, sink,
@@ -552,7 +556,10 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
                if (!fmd->fimc_lite[i])
                        continue;
 
-               flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
+               if (link_mask & (1 << (i + FIMC_MAX_DEVS)))
+                       flags = MEDIA_LNK_FL_ENABLED;
+               else
+                       flags = 0;
 
                sink = &fmd->fimc_lite[i]->subdev.entity;
                ret = media_entity_create_link(source, pad, sink,
@@ -614,9 +621,8 @@ static int fimc_md_create_links(struct fimc_md *fmd)
        struct s5p_fimc_isp_info *pdata;
        struct fimc_sensor_info *s_info;
        struct media_entity *source, *sink;
-       int i, pad, fimc_id = 0;
-       int ret = 0;
-       u32 flags;
+       int i, pad, fimc_id = 0, ret = 0;
+       u32 flags, link_mask = 0;
 
        for (i = 0; i < fmd->num_sensors; i++) {
                if (fmd->sensor[i].subdev == NULL)
@@ -668,19 +674,20 @@ static int fimc_md_create_links(struct fimc_md *fmd)
                if (source == NULL)
                        continue;
 
+               link_mask = 1 << fimc_id++;
                ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
-                                                      pad, fimc_id++);
+                                                      pad, link_mask);
        }
 
-       fimc_id = 0;
        for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
                if (fmd->csis[i].sd == NULL)
                        continue;
                source = &fmd->csis[i].sd->entity;
                pad = CSIS_PAD_SOURCE;
 
+               link_mask = 1 << fimc_id++;
                ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL,
-                                                      pad, fimc_id++);
+                                                      pad, link_mask);
        }
 
        /* Create immutable links between each FIMC's subdev and video node */
@@ -734,8 +741,8 @@ static void fimc_md_put_clocks(struct fimc_md *fmd)
 }
 
 static int __fimc_md_set_camclk(struct fimc_md *fmd,
-                                        struct fimc_sensor_info *s_info,
-                                        bool on)
+                               struct fimc_sensor_info *s_info,
+                               bool on)
 {
        struct s5p_fimc_isp_info *pdata = s_info->pdata;
        struct fimc_camclk_info *camclk;
@@ -744,12 +751,10 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
        if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL)
                return -EINVAL;
 
-       if (s_info->clk_on == on)
-               return 0;
        camclk = &fmd->camclk[pdata->clk_id];
 
-       dbg("camclk %d, f: %lu, clk: %p, on: %d",
-           pdata->clk_id, pdata->clk_frequency, camclk, on);
+       dbg("camclk %d, f: %lu, use_count: %d, on: %d",
+           pdata->clk_id, pdata->clk_frequency, camclk->use_count, on);
 
        if (on) {
                if (camclk->use_count > 0 &&
@@ -760,11 +765,9 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
                        clk_set_rate(camclk->clock, pdata->clk_frequency);
                        camclk->frequency = pdata->clk_frequency;
                        ret = clk_enable(camclk->clock);
+                       dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
+                           clk_get_rate(camclk->clock));
                }
-               s_info->clk_on = 1;
-               dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
-                   clk_get_rate(camclk->clock));
-
                return ret;
        }
 
@@ -773,7 +776,6 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
 
        if (--camclk->use_count == 0) {
                clk_disable(camclk->clock);
-               s_info->clk_on = 0;
                dbg("Disabled camclk %d", pdata->clk_id);
        }
        return ret;
@@ -789,8 +791,6 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
  * devices to which sensors can be attached, either directly or through
  * the MIPI CSI receiver. The clock is allowed here to be used by
  * multiple sensors concurrently if they use same frequency.
- * The per sensor subdev clk_on attribute helps to synchronize accesses
- * to the sclk_cam clocks from the video and media device nodes.
  * This function should only be called when the graph mutex is held.
  */
 int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
index 3b8a3492a17671fc86658db8eb410861e8cba8f2..1f5dbaff5442a7df686b4e6dc023952b8436939f 100644 (file)
@@ -47,7 +47,6 @@ struct fimc_camclk_info {
  * @pdata: sensor's atrributes passed as media device's platform data
  * @subdev: image sensor v4l2 subdev
  * @host: fimc device the sensor is currently linked to
- * @clk_on: sclk_cam clock's state associated with this subdev
  *
  * This data structure applies to image sensor and the writeback subdevs.
  */
@@ -55,7 +54,6 @@ struct fimc_sensor_info {
        struct s5p_fimc_isp_info *pdata;
        struct v4l2_subdev *subdev;
        struct fimc_dev *host;
-       bool clk_on;
 };
 
 /**
index 4dd32fc8fd82c740a8db84853e0e8e3422e6d238..feea867f318c25a6bce189d2bf6e95fb91a42422 100644 (file)
@@ -996,6 +996,7 @@ int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
 
        for (i = 0; i < NUM_CTRLS; i++) {
                if (IS_MFC51_PRIV(controls[i].id)) {
+                       memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
                        cfg.ops = &s5p_mfc_dec_ctrl_ops;
                        cfg.id = controls[i].id;
                        cfg.min = controls[i].minimum;
index 03d83340e7fb6bcaaded17b1da810610a8c40ad7..158b78989b89dc43dd7ced55dec2ca91a6baa28e 100644 (file)
@@ -1773,6 +1773,7 @@ int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
        }
        for (i = 0; i < NUM_CTRLS; i++) {
                if (IS_MFC51_PRIV(controls[i].id)) {
+                       memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
                        cfg.ops = &s5p_mfc_enc_ctrl_ops;
                        cfg.id = controls[i].id;
                        cfg.min = controls[i].minimum;
index e8c93c89265a22e7d4fad6e8e7f59d3511abeca9..9cf5bda35fbe1cfe332e8b18ae3d9218b3e8f54b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/device.h>
 #include <linux/gpio.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/v4l2-mediabus.h>
index 83dbb2ddff10780325e92144d495dbabd821294f..0cbada18f6f57376d980d34345335279499fec03 100644 (file)
@@ -681,6 +681,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
        SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
        SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings);
        SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings);
+       SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap);
        /* yes, really vidioc_subscribe_event */
        SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
        SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
index d7166afc255edf06ea7396b6efc12b91da92fca3..ca2754a3cd63d83eefb8927ae072f6732e852716 100644 (file)
@@ -172,8 +172,10 @@ struct zoran_jpg_settings {
        struct v4l2_jpegcompression jpg_comp;   /* JPEG-specific capture settings */
 };
 
+struct zoran_fh;
+
 struct zoran_mapping {
-       struct file *file;
+       struct zoran_fh *fh;
        int count;
 };
 
index c573109318108cac4ffea8d27488943ab3b7bac8..c6ccdeb6d8d6e50bb0db8c624c97e7b19ca9b7ac 100644 (file)
@@ -2811,7 +2811,7 @@ static void
 zoran_vm_close (struct vm_area_struct *vma)
 {
        struct zoran_mapping *map = vma->vm_private_data;
-       struct zoran_fh *fh = map->file->private_data;
+       struct zoran_fh *fh = map->fh;
        struct zoran *zr = fh->zr;
        int i;
 
@@ -2938,7 +2938,7 @@ zoran_mmap (struct file           *file,
                res = -ENOMEM;
                goto mmap_unlock_and_return;
        }
-       map->file = file;
+       map->fh = fh;
        map->count = 1;
 
        vma->vm_ops = &zoran_vm_ops;
index e129c820df7da7d6430e62891558f92cdbe235ab..92144ed1ad469d8257eab6636c4d7f8cc4c65180 100644 (file)
@@ -286,6 +286,7 @@ config TWL6040_CORE
        depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        select REGMAP_I2C
+       select IRQ_DOMAIN
        default n
        help
          Say yes here if you want support for Texas Instruments TWL6040 audio
diff --git a/drivers/mfd/ab5500-core.h b/drivers/mfd/ab5500-core.h
deleted file mode 100644 (file)
index 63b30b1..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Shared definitions and data structures for the AB5500 MFD driver
- */
-
-/* Read/write operation values. */
-#define AB5500_PERM_RD (0x01)
-#define AB5500_PERM_WR (0x02)
-
-/* Read/write permissions. */
-#define AB5500_PERM_RO (AB5500_PERM_RD)
-#define AB5500_PERM_RW (AB5500_PERM_RD | AB5500_PERM_WR)
-
-#define AB5500_MASK_BASE (0x60)
-#define AB5500_MASK_END (0x79)
-#define AB5500_CHIP_ID (0x20)
-
-/**
- * struct ab5500_reg_range
- * @first: the first address of the range
- * @last: the last address of the range
- * @perm: access permissions for the range
- */
-struct ab5500_reg_range {
-       u8 first;
-       u8 last;
-       u8 perm;
-};
-
-/**
- * struct ab5500_i2c_ranges
- * @count: the number of ranges in the list
- * @range: the list of register ranges
- */
-struct ab5500_i2c_ranges {
-       u8 nranges;
-       u8 bankid;
-       const struct ab5500_reg_range *range;
-};
-
-/**
- * struct ab5500_i2c_banks
- * @count: the number of ranges in the list
- * @range: the list of register ranges
- */
-struct ab5500_i2c_banks {
-       u8 nbanks;
-       const struct ab5500_i2c_ranges *bank;
-};
-
-/**
- * struct ab5500_bank
- * @slave_addr: I2C slave_addr found in AB5500 specification
- * @name: Documentation name of the bank. For reference
- */
-struct ab5500_bank {
-       u8 slave_addr;
-       const char *name;
-};
-
-static const struct ab5500_bank bankinfo[AB5500_NUM_BANKS] = {
-       [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
-               AB5500_ADDR_VIT_IO_I2C_CLK_TST_OTP, "VIT_IO_I2C_CLK_TST_OTP"},
-       [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
-               AB5500_ADDR_VDDDIG_IO_I2C_CLK_TST, "VDDDIG_IO_I2C_CLK_TST"},
-       [AB5500_BANK_VDENC] = {AB5500_ADDR_VDENC, "VDENC"},
-       [AB5500_BANK_SIM_USBSIM] = {AB5500_ADDR_SIM_USBSIM, "SIM_USBSIM"},
-       [AB5500_BANK_LED] = {AB5500_ADDR_LED, "LED"},
-       [AB5500_BANK_ADC] = {AB5500_ADDR_ADC, "ADC"},
-       [AB5500_BANK_RTC] = {AB5500_ADDR_RTC, "RTC"},
-       [AB5500_BANK_STARTUP] = {AB5500_ADDR_STARTUP, "STARTUP"},
-       [AB5500_BANK_DBI_ECI] = {AB5500_ADDR_DBI_ECI, "DBI-ECI"},
-       [AB5500_BANK_CHG] = {AB5500_ADDR_CHG, "CHG"},
-       [AB5500_BANK_FG_BATTCOM_ACC] = {
-               AB5500_ADDR_FG_BATTCOM_ACC, "FG_BATCOM_ACC"},
-       [AB5500_BANK_USB] = {AB5500_ADDR_USB, "USB"},
-       [AB5500_BANK_IT] = {AB5500_ADDR_IT, "IT"},
-       [AB5500_BANK_VIBRA] = {AB5500_ADDR_VIBRA, "VIBRA"},
-       [AB5500_BANK_AUDIO_HEADSETUSB] = {
-               AB5500_ADDR_AUDIO_HEADSETUSB, "AUDIO_HEADSETUSB"},
-};
-
-int ab5500_get_register_interruptible_raw(struct ab5500 *ab, u8 bank, u8 reg,
-       u8 *value);
-int ab5500_mask_and_set_register_interruptible_raw(struct ab5500 *ab, u8 bank,
-       u8 reg, u8 bitmask, u8 bitvalues);
index 3fcdab3eb8eb67fb02a08c02166613e11742924c..03df422feb763ab075ac5fa741ef09b71c066d1d 100644 (file)
@@ -49,10 +49,72 @@ static struct regmap_config mc13xxx_regmap_spi_config = {
        .reg_bits = 7,
        .pad_bits = 1,
        .val_bits = 24,
+       .write_flag_mask = 0x80,
 
        .max_register = MC13XXX_NUMREGS,
 
        .cache_type = REGCACHE_NONE,
+       .use_single_rw = 1,
+};
+
+static int mc13xxx_spi_read(void *context, const void *reg, size_t reg_size,
+                               void *val, size_t val_size)
+{
+       unsigned char w[4] = { *((unsigned char *) reg), 0, 0, 0};
+       unsigned char r[4];
+       unsigned char *p = val;
+       struct device *dev = context;
+       struct spi_device *spi = to_spi_device(dev);
+       struct spi_transfer t = {
+               .tx_buf = w,
+               .rx_buf = r,
+               .len = 4,
+       };
+
+       struct spi_message m;
+       int ret;
+
+       if (val_size != 3 || reg_size != 1)
+               return -ENOTSUPP;
+
+       spi_message_init(&m);
+       spi_message_add_tail(&t, &m);
+       ret = spi_sync(spi, &m);
+
+       memcpy(p, &r[1], 3);
+
+       return ret;
+}
+
+static int mc13xxx_spi_write(void *context, const void *data, size_t count)
+{
+       struct device *dev = context;
+       struct spi_device *spi = to_spi_device(dev);
+
+       if (count != 4)
+               return -ENOTSUPP;
+
+       return spi_write(spi, data, count);
+}
+
+/*
+ * We cannot use regmap-spi generic bus implementation here.
+ * The MC13783 chip will get corrupted if CS signal is deasserted
+ * and on i.Mx31 SoC (the target SoC for MC13783 PMIC) the SPI controller
+ * has the following errata (DSPhl22960):
+ * "The CSPI negates SS when the FIFO becomes empty with
+ * SSCTL= 0. Software cannot guarantee that the FIFO will not
+ * drain because of higher priority interrupts and the
+ * non-realtime characteristics of the operating system. As a
+ * result, the SS will negate before all of the data has been
+ * transferred to/from the peripheral."
+ * We workaround this by accessing the SPI controller with a
+ * single transfert.
+ */
+
+static struct regmap_bus regmap_mc13xxx_bus = {
+       .write = mc13xxx_spi_write,
+       .read = mc13xxx_spi_read,
 };
 
 static int mc13xxx_spi_probe(struct spi_device *spi)
@@ -73,12 +135,13 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
 
        dev_set_drvdata(&spi->dev, mc13xxx);
        spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
-       spi->bits_per_word = 32;
 
        mc13xxx->dev = &spi->dev;
        mutex_init(&mc13xxx->lock);
 
-       mc13xxx->regmap = regmap_init_spi(spi, &mc13xxx_regmap_spi_config);
+       mc13xxx->regmap = regmap_init(&spi->dev, &regmap_mc13xxx_bus, &spi->dev,
+                                       &mc13xxx_regmap_spi_config);
+
        if (IS_ERR(mc13xxx->regmap)) {
                ret = PTR_ERR(mc13xxx->regmap);
                dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
index 7e96bb2297244f7946537a5da5f78226e6a4db40..41088ecbb2a92e3c6350038ad61f77ceb500e8ce 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
+#include <linux/gpio.h>
 #include <plat/cpu.h>
 #include <plat/usb.h>
 #include <linux/pm_runtime.h>
@@ -500,8 +501,21 @@ static void omap_usbhs_init(struct device *dev)
        dev_dbg(dev, "starting TI HSUSB Controller\n");
 
        pm_runtime_get_sync(dev);
-       spin_lock_irqsave(&omap->lock, flags);
 
+       if (pdata->ehci_data->phy_reset) {
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+                       gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
+                                        GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+                       gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
+                                        GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+
+               /* Hold the PHY in RESET for enough time till DIR is high */
+               udelay(10);
+       }
+
+       spin_lock_irqsave(&omap->lock, flags);
        omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
        dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
 
@@ -581,9 +595,39 @@ static void omap_usbhs_init(struct device *dev)
        }
 
        spin_unlock_irqrestore(&omap->lock, flags);
+
+       if (pdata->ehci_data->phy_reset) {
+               /* Hold the PHY in RESET for enough time till
+                * PHY is settled and ready
+                */
+               udelay(10);
+
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+                       gpio_set_value_cansleep
+                               (pdata->ehci_data->reset_gpio_port[0], 1);
+
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+                       gpio_set_value_cansleep
+                               (pdata->ehci_data->reset_gpio_port[1], 1);
+       }
+
        pm_runtime_put_sync(dev);
 }
 
+static void omap_usbhs_deinit(struct device *dev)
+{
+       struct usbhs_hcd_omap           *omap = dev_get_drvdata(dev);
+       struct usbhs_omap_platform_data *pdata = &omap->platdata;
+
+       if (pdata->ehci_data->phy_reset) {
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+                       gpio_free(pdata->ehci_data->reset_gpio_port[0]);
+
+               if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+                       gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+       }
+}
+
 
 /**
  * usbhs_omap_probe - initialize TI-based HCDs
@@ -767,6 +811,7 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
        goto end_probe;
 
 err_alloc:
+       omap_usbhs_deinit(&pdev->dev);
        iounmap(omap->tll_base);
 
 err_tll:
@@ -818,6 +863,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
 {
        struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
 
+       omap_usbhs_deinit(&pdev->dev);
        iounmap(omap->tll_base);
        iounmap(omap->uhh_base);
        clk_put(omap->init_60m_fclk);
index 00c0aba7eba000de65742b04014419e0115c6eba..c4a69f193a1df1985abfbaeeffb8e39cda933493 100644 (file)
@@ -356,7 +356,14 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
                }
        }
 
-       ret = regmap_add_irq_chip(palmas->regmap[1], palmas->irq,
+       /* Change IRQ into clear on read mode for efficiency */
+       slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE);
+       addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, PALMAS_INT_CTRL);
+       reg = PALMAS_INT_CTRL_INT_CLEAR;
+
+       regmap_write(palmas->regmap[slave], addr, reg);
+
+       ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq,
                        IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip,
                        &palmas->irq_data);
        if (ret < 0)
@@ -441,6 +448,9 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c,
                goto err;
        }
 
+       children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata;
+       children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata);
+
        ret = mfd_add_devices(palmas->dev, -1,
                              children, ARRAY_SIZE(palmas_children),
                              NULL, regmap_irq_chip_get_base(palmas->irq_data));
@@ -472,6 +482,7 @@ static const struct i2c_device_id palmas_i2c_id[] = {
        { "twl6035", },
        { "twl6037", },
        { "tps65913", },
+       { /* end */ }
 };
 MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
 
index db194e433c085358b8d4716f062af3700bba1956..61c097a98f5de7eb45fd0ccb8fdc44dd53c869fa 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/regmap.h>
 #include <linux/err.h>
+#include <linux/regulator/of_regulator.h>
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps65217.h>
@@ -132,6 +133,61 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
 }
 EXPORT_SYMBOL_GPL(tps65217_clear_bits);
 
+#ifdef CONFIG_OF
+static struct of_regulator_match reg_matches[] = {
+       { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 },
+       { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 },
+       { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 },
+       { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 },
+       { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 },
+       { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 },
+       { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 },
+};
+
+static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
+{
+       struct device_node *node = client->dev.of_node;
+       struct tps65217_board *pdata;
+       struct device_node *regs;
+       int count = ARRAY_SIZE(reg_matches);
+       int ret, i;
+
+       regs = of_find_node_by_name(node, "regulators");
+       if (!regs)
+               return NULL;
+
+       ret = of_regulator_match(&client->dev, regs, reg_matches, count);
+       of_node_put(regs);
+       if ((ret < 0) || (ret > count))
+               return NULL;
+
+       count = ret;
+       pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       for (i = 0; i < count; i++) {
+               if (!reg_matches[i].init_data || !reg_matches[i].of_node)
+                       continue;
+
+               pdata->tps65217_init_data[i] = reg_matches[i].init_data;
+               pdata->of_node[i] = reg_matches[i].of_node;
+       }
+
+       return pdata;
+}
+
+static struct of_device_id tps65217_of_match[] = {
+       { .compatible = "ti,tps65217", },
+       { },
+};
+#else
+static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client)
+{
+       return NULL;
+}
+#endif
+
 static struct regmap_config tps65217_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -141,10 +197,14 @@ static int __devinit tps65217_probe(struct i2c_client *client,
                                const struct i2c_device_id *ids)
 {
        struct tps65217 *tps;
+       struct regulator_init_data *reg_data;
        struct tps65217_board *pdata = client->dev.platform_data;
        int i, ret;
        unsigned int version;
 
+       if (!pdata && client->dev.of_node)
+               pdata = tps65217_parse_dt(client);
+
        tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
        if (!tps)
                return -ENOMEM;
@@ -182,8 +242,9 @@ static int __devinit tps65217_probe(struct i2c_client *client,
                }
 
                pdev->dev.parent = tps->dev;
-               platform_device_add_data(pdev, &pdata->tps65217_init_data[i],
-                                       sizeof(pdata->tps65217_init_data[i]));
+               pdev->dev.of_node = pdata->of_node[i];
+               reg_data = pdata->tps65217_init_data[i];
+               platform_device_add_data(pdev, reg_data, sizeof(*reg_data));
                tps->regulator_pdev[i] = pdev;
 
                platform_device_add(pdev);
@@ -212,6 +273,8 @@ MODULE_DEVICE_TABLE(i2c, tps65217_id_table);
 static struct i2c_driver tps65217_driver = {
        .driver         = {
                .name   = "tps65217",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(tps65217_of_match),
        },
        .id_table       = tps65217_id_table,
        .probe          = tps65217_probe,
index 7de13891e49e8f2c788ad2e7ca274f257e1c41f5..783fcd7365bc1e770739db884bba4a5088479e22 100644 (file)
@@ -1147,7 +1147,7 @@ static int mei_pci_resume(struct device *device)
                err = request_threaded_irq(pdev->irq,
                        NULL,
                        mei_interrupt_thread_handler,
-                       0, mei_driver_name, dev);
+                       IRQF_ONESHOT, mei_driver_name, dev);
        else
                err = request_threaded_irq(pdev->irq,
                        mei_interrupt_quick_handler,
index 17bbacb1b4b131b119b0076b339f44012fcc51f7..87b251ab6ec582f2c8177687d0b330d97110fb50 100644 (file)
@@ -452,9 +452,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part,
 
                if (msg->activate_gru_mq_desc_gpa !=
                    part_uv->activate_gru_mq_desc_gpa) {
-                       spin_lock_irqsave(&part_uv->flags_lock, irq_flags);
+                       spin_lock(&part_uv->flags_lock);
                        part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV;
-                       spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags);
+                       spin_unlock(&part_uv->flags_lock);
                        part_uv->activate_gru_mq_desc_gpa =
                            msg->activate_gru_mq_desc_gpa;
                }
index 276d21ce6bc1ba6a18c844258331d6417f6278d7..f1c84decb192638e02aa13488e58c855d7335704 100644 (file)
@@ -850,9 +850,7 @@ out:
                goto retry;
        if (!err)
                mmc_blk_reset_success(md, type);
-       spin_lock_irq(&md->lock);
-       __blk_end_request(req, err, blk_rq_bytes(req));
-       spin_unlock_irq(&md->lock);
+       blk_end_request(req, err, blk_rq_bytes(req));
 
        return err ? 0 : 1;
 }
@@ -934,9 +932,7 @@ out_retry:
        if (!err)
                mmc_blk_reset_success(md, type);
 out:
-       spin_lock_irq(&md->lock);
-       __blk_end_request(req, err, blk_rq_bytes(req));
-       spin_unlock_irq(&md->lock);
+       blk_end_request(req, err, blk_rq_bytes(req));
 
        return err ? 0 : 1;
 }
@@ -951,9 +947,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
        if (ret)
                ret = -EIO;
 
-       spin_lock_irq(&md->lock);
-       __blk_end_request_all(req, ret);
-       spin_unlock_irq(&md->lock);
+       blk_end_request_all(req, ret);
 
        return ret ? 0 : 1;
 }
@@ -1252,14 +1246,10 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
 
                blocks = mmc_sd_num_wr_blocks(card);
                if (blocks != (u32)-1) {
-                       spin_lock_irq(&md->lock);
-                       ret = __blk_end_request(req, 0, blocks << 9);
-                       spin_unlock_irq(&md->lock);
+                       ret = blk_end_request(req, 0, blocks << 9);
                }
        } else {
-               spin_lock_irq(&md->lock);
-               ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
-               spin_unlock_irq(&md->lock);
+               ret = blk_end_request(req, 0, brq->data.bytes_xfered);
        }
        return ret;
 }
@@ -1311,10 +1301,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                         * A block was successfully transferred.
                         */
                        mmc_blk_reset_success(md, type);
-                       spin_lock_irq(&md->lock);
-                       ret = __blk_end_request(req, 0,
+                       ret = blk_end_request(req, 0,
                                                brq->data.bytes_xfered);
-                       spin_unlock_irq(&md->lock);
                        /*
                         * If the blk_end_request function returns non-zero even
                         * though all data has been transferred and no errors
@@ -1364,10 +1352,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
                         * time, so we only reach here after trying to
                         * read a single sector.
                         */
-                       spin_lock_irq(&md->lock);
-                       ret = __blk_end_request(req, -EIO,
+                       ret = blk_end_request(req, -EIO,
                                                brq->data.blksz);
-                       spin_unlock_irq(&md->lock);
                        if (!ret)
                                goto start_new_req;
                        break;
@@ -1388,12 +1374,10 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
        return 1;
 
  cmd_abort:
-       spin_lock_irq(&md->lock);
        if (mmc_card_removed(card))
                req->cmd_flags |= REQ_QUIET;
        while (ret)
-               ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
-       spin_unlock_irq(&md->lock);
+               ret = blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
 
  start_new_req:
        if (rqc) {
@@ -1417,9 +1401,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        ret = mmc_blk_part_switch(card, md);
        if (ret) {
                if (req) {
-                       spin_lock_irq(&md->lock);
-                       __blk_end_request_all(req, -EIO);
-                       spin_unlock_irq(&md->lock);
+                       blk_end_request_all(req, -EIO);
                }
                ret = 0;
                goto out;
index dca4428380f15c53adf73ce79810e7e26c0543f9..38ed210ce2f3b38475f3baf6e08f331e25a73675 100644 (file)
@@ -7,6 +7,6 @@ mmc_core-y                      := core.o bus.o host.o \
                                   mmc.o mmc_ops.o sd.o sd_ops.o \
                                   sdio.o sdio_ops.o sdio_bus.o \
                                   sdio_cis.o sdio_io.o sdio_irq.o \
-                                  quirks.o cd-gpio.o
+                                  quirks.o slot-gpio.o
 
 mmc_core-$(CONFIG_DEBUG_FS)    += debugfs.o
diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c
deleted file mode 100644 (file)
index f13e38d..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Generic GPIO card-detect helper
- *
- * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/mmc/cd-gpio.h>
-#include <linux/mmc/host.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-struct mmc_cd_gpio {
-       unsigned int gpio;
-       char label[0];
-};
-
-static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
-{
-       /* Schedule a card detection after a debounce timeout */
-       mmc_detect_change(dev_id, msecs_to_jiffies(100));
-       return IRQ_HANDLED;
-}
-
-int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio)
-{
-       size_t len = strlen(dev_name(host->parent)) + 4;
-       struct mmc_cd_gpio *cd;
-       int irq = gpio_to_irq(gpio);
-       int ret;
-
-       if (irq < 0)
-               return irq;
-
-       cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
-       if (!cd)
-               return -ENOMEM;
-
-       snprintf(cd->label, len, "%s cd", dev_name(host->parent));
-
-       ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label);
-       if (ret < 0)
-               goto egpioreq;
-
-       ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
-                                  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                                  cd->label, host);
-       if (ret < 0)
-               goto eirqreq;
-
-       cd->gpio = gpio;
-       host->hotplug.irq = irq;
-       host->hotplug.handler_priv = cd;
-
-       return 0;
-
-eirqreq:
-       gpio_free(gpio);
-egpioreq:
-       kfree(cd);
-       return ret;
-}
-EXPORT_SYMBOL(mmc_cd_gpio_request);
-
-void mmc_cd_gpio_free(struct mmc_host *host)
-{
-       struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
-
-       if (!cd)
-               return;
-
-       free_irq(host->hotplug.irq, host);
-       gpio_free(cd->gpio);
-       kfree(cd);
-}
-EXPORT_SYMBOL(mmc_cd_gpio_free);
index 0b6141d29dbd1d9a3f146f2bb1b9923be9e0ad84..8ac5246e2ab2bc85a6ba82ee0a0eab732130fdf6 100644 (file)
@@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
 {
        int err;
        u32 status;
+       unsigned long prg_wait;
 
        BUG_ON(!card);
 
@@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card)
                goto out;
        }
 
-       /*
-        * If the card status is in PRG-state, we can send the HPI command.
-        */
-       if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
-               do {
-                       /*
-                        * We don't know when the HPI command will finish
-                        * processing, so we need to resend HPI until out
-                        * of prg-state, and keep checking the card status
-                        * with SEND_STATUS.  If a timeout error occurs when
-                        * sending the HPI command, we are already out of
-                        * prg-state.
-                        */
-                       err = mmc_send_hpi_cmd(card, &status);
-                       if (err)
-                               pr_debug("%s: abort HPI (%d error)\n",
-                                        mmc_hostname(card->host), err);
+       switch (R1_CURRENT_STATE(status)) {
+       case R1_STATE_IDLE:
+       case R1_STATE_READY:
+       case R1_STATE_STBY:
+               /*
+                * In idle states, HPI is not needed and the caller
+                * can issue the next intended command immediately
+                */
+               goto out;
+       case R1_STATE_PRG:
+               break;
+       default:
+               /* In all other states, it's illegal to issue HPI */
+               pr_debug("%s: HPI cannot be sent. Card state=%d\n",
+                       mmc_hostname(card->host), R1_CURRENT_STATE(status));
+               err = -EINVAL;
+               goto out;
+       }
 
-                       err = mmc_send_status(card, &status);
-                       if (err)
-                               break;
-               } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
-       } else
-               pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+       err = mmc_send_hpi_cmd(card, &status);
+       if (err)
+               goto out;
+
+       prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
+       do {
+               err = mmc_send_status(card, &status);
+
+               if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
+                       break;
+               if (time_after(jiffies, prg_wait))
+                       err = -ETIMEDOUT;
+       } while (!err);
 
 out:
        mmc_release_host(card->host);
@@ -941,7 +950,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply)
 
        return result;
 }
-EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
+EXPORT_SYMBOL_GPL(mmc_regulator_get_ocrmask);
 
 /**
  * mmc_regulator_set_ocr - set regulator to match host->ios voltage
@@ -1011,7 +1020,30 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
                        "could not set regulator OCR (%d)\n", result);
        return result;
 }
-EXPORT_SYMBOL(mmc_regulator_set_ocr);
+EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
+
+int mmc_regulator_get_supply(struct mmc_host *mmc)
+{
+       struct device *dev = mmc_dev(mmc);
+       struct regulator *supply;
+       int ret;
+
+       supply = devm_regulator_get(dev, "vmmc");
+       mmc->supply.vmmc = supply;
+       mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc");
+
+       if (IS_ERR(supply))
+               return PTR_ERR(supply);
+
+       ret = mmc_regulator_get_ocrmask(supply);
+       if (ret > 0)
+               mmc->ocr_avail = ret;
+       else
+               dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
 
 #endif /* CONFIG_REGULATOR */
 
@@ -1180,6 +1212,9 @@ static void mmc_power_up(struct mmc_host *host)
        host->ios.timing = MMC_TIMING_LEGACY;
        mmc_set_ios(host);
 
+       /* Set signal voltage to 3.3V */
+       mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
+
        /*
         * This delay should be sufficient to allow the power supply
         * to reach the minimum voltage.
@@ -1931,9 +1966,6 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
         */
        mmc_hw_reset_for_init(host);
 
-       /* Initialization should be done at 3.3 V I/O voltage. */
-       mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
        /*
         * sdio_reset sends CMD52 to reset card.  Since we do not know
         * if the card is being re-initialized, just send it.  CMD52
@@ -2075,6 +2107,7 @@ void mmc_rescan(struct work_struct *work)
 void mmc_start_host(struct mmc_host *host)
 {
        host->f_init = max(freqs[0], host->f_min);
+       host->rescan_disable = 0;
        mmc_power_up(host);
        mmc_detect_change(host, 0);
 }
@@ -2088,6 +2121,7 @@ void mmc_stop_host(struct mmc_host *host)
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
+       host->rescan_disable = 1;
        cancel_delayed_work_sync(&host->detect);
        mmc_flush_scheduled_work();
 
index 91c84c7a1829e8693c4e9dc652758512df22b4d6..597f189b44278caa4edd682ef27b6c57066eb1f2 100644 (file)
@@ -32,6 +32,7 @@
 static void mmc_host_classdev_release(struct device *dev)
 {
        struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       mutex_destroy(&host->slot.lock);
        kfree(host);
 }
 
@@ -312,6 +313,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
        if (!host)
                return NULL;
 
+       /* scanning will be enabled when we're ready */
+       host->rescan_disable = 1;
        spin_lock(&mmc_host_lock);
        err = idr_get_new(&mmc_host_idr, host, &host->index);
        spin_unlock(&mmc_host_lock);
@@ -327,6 +330,9 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 
        mmc_host_clk_init(host);
 
+       mutex_init(&host->slot.lock);
+       host->slot.cd_irq = -EINVAL;
+
        spin_lock_init(&host->lock);
        init_waitqueue_head(&host->wq);
        INIT_DELAYED_WORK(&host->detect, mmc_rescan);
index 258b203397aa88a381a9e4f007eacf77b9452aa3..396b25891bb90b59083adeb85769971b6c3057b0 100644 (file)
@@ -717,10 +717,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
                                 card->ext_csd.generic_cmd6_time);
        }
 
-       if (err)
-               pr_err("%s: power class selection for ext_csd_bus_width %d"
-                      " failed\n", mmc_hostname(card->host), bus_width);
-
        return err;
 }
 
@@ -822,9 +818,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        if (!mmc_host_is_spi(host))
                mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
 
-       /* Initialization should be done at 3.3 V I/O voltage. */
-       mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
        /*
         * Since we're changing the OCR value, we seem to
         * need to tell some cards to go back to the idle
@@ -1104,7 +1097,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
                err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
                if (err)
-                       goto err;
+                       pr_warning("%s: power class selection to bus width %d"
+                                  " failed\n", mmc_hostname(card->host),
+                                  1 << bus_width);
        }
 
        /*
@@ -1136,7 +1131,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
                                                    ext_csd);
                        if (err)
-                               goto err;
+                               pr_warning("%s: power class selection to "
+                                          "bus width %d failed\n",
+                                          mmc_hostname(card->host),
+                                          1 << bus_width);
 
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                         EXT_CSD_BUS_WIDTH,
@@ -1164,7 +1162,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
                                                    ext_csd);
                        if (err)
-                               goto err;
+                               pr_warning("%s: power class selection to "
+                                          "bus width %d ddr %d failed\n",
+                                          mmc_hostname(card->host),
+                                          1 << bus_width, ddr);
 
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                         EXT_CSD_BUS_WIDTH,
index 69370f494e054f7951d287bba8b1d570510dc33d..0ed2cc5f35b662dcded214fba101fa2f5a042c92 100644 (file)
@@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
 
        cmd.opcode = opcode;
        cmd.arg = card->rca << 16 | 1;
-       cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
 
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
index b2b43f624b9edd13a8ad4d836ec2229636de2a9c..74972c241dff38751d5be3e0e653336e7e8892a5 100644 (file)
@@ -244,7 +244,7 @@ static int mmc_read_ssr(struct mmc_card *card)
         * bitfield positions accordingly.
         */
        au = UNSTUFF_BITS(ssr, 428 - 384, 4);
-       if (au > 0 || au <= 9) {
+       if (au > 0 && au <= 9) {
                card->ssr.au = 1 << (au + 4);
                es = UNSTUFF_BITS(ssr, 408 - 384, 16);
                et = UNSTUFF_BITS(ssr, 402 - 384, 6);
@@ -290,8 +290,12 @@ static int mmc_read_switch(struct mmc_card *card)
                return -ENOMEM;
        }
 
-       /* Find out the supported Bus Speed Modes. */
-       err = mmc_sd_switch(card, 0, 0, 1, status);
+       /*
+        * Find out the card's support bits with a mode 0 operation.
+        * The argument does not matter, as the support bits do not
+        * change with the arguments.
+        */
+       err = mmc_sd_switch(card, 0, 0, 0, status);
        if (err) {
                /*
                 * If the host or the card can't do the switch,
@@ -312,46 +316,8 @@ static int mmc_read_switch(struct mmc_card *card)
 
        if (card->scr.sda_spec3) {
                card->sw_caps.sd3_bus_mode = status[13];
-
-               /* Find out Driver Strengths supported by the card */
-               err = mmc_sd_switch(card, 0, 2, 1, status);
-               if (err) {
-                       /*
-                        * If the host or the card can't do the switch,
-                        * fail more gracefully.
-                        */
-                       if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
-                               goto out;
-
-                       pr_warning("%s: problem reading "
-                               "Driver Strength.\n",
-                               mmc_hostname(card->host));
-                       err = 0;
-
-                       goto out;
-               }
-
+               /* Driver Strengths supported by the card */
                card->sw_caps.sd3_drv_type = status[9];
-
-               /* Find out Current Limits supported by the card */
-               err = mmc_sd_switch(card, 0, 3, 1, status);
-               if (err) {
-                       /*
-                        * If the host or the card can't do the switch,
-                        * fail more gracefully.
-                        */
-                       if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
-                               goto out;
-
-                       pr_warning("%s: problem reading "
-                               "Current Limit.\n",
-                               mmc_hostname(card->host));
-                       err = 0;
-
-                       goto out;
-               }
-
-               card->sw_caps.sd3_curr_limit = status[7];
        }
 
 out:
@@ -551,60 +517,80 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
        return 0;
 }
 
+/* Get host's max current setting at its current voltage */
+static u32 sd_get_host_max_current(struct mmc_host *host)
+{
+       u32 voltage, max_current;
+
+       voltage = 1 << host->ios.vdd;
+       switch (voltage) {
+       case MMC_VDD_165_195:
+               max_current = host->max_current_180;
+               break;
+       case MMC_VDD_29_30:
+       case MMC_VDD_30_31:
+               max_current = host->max_current_300;
+               break;
+       case MMC_VDD_32_33:
+       case MMC_VDD_33_34:
+               max_current = host->max_current_330;
+               break;
+       default:
+               max_current = 0;
+       }
+
+       return max_current;
+}
+
 static int sd_set_current_limit(struct mmc_card *card, u8 *status)
 {
-       int current_limit = 0;
+       int current_limit = SD_SET_CURRENT_NO_CHANGE;
        int err;
+       u32 max_current;
 
        /*
         * Current limit switch is only defined for SDR50, SDR104, and DDR50
-        * bus speed modes. For other bus speed modes, we set the default
-        * current limit of 200mA.
+        * bus speed modes. For other bus speed modes, we do not change the
+        * current limit.
         */
-       if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
-           (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
-           (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
-               if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
-                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
-                               current_limit = SD_SET_CURRENT_LIMIT_800;
-                       else if (card->sw_caps.sd3_curr_limit &
-                                       SD_MAX_CURRENT_600)
-                               current_limit = SD_SET_CURRENT_LIMIT_600;
-                       else if (card->sw_caps.sd3_curr_limit &
-                                       SD_MAX_CURRENT_400)
-                               current_limit = SD_SET_CURRENT_LIMIT_400;
-                       else if (card->sw_caps.sd3_curr_limit &
-                                       SD_MAX_CURRENT_200)
-                               current_limit = SD_SET_CURRENT_LIMIT_200;
-               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
-                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
-                               current_limit = SD_SET_CURRENT_LIMIT_600;
-                       else if (card->sw_caps.sd3_curr_limit &
-                                       SD_MAX_CURRENT_400)
-                               current_limit = SD_SET_CURRENT_LIMIT_400;
-                       else if (card->sw_caps.sd3_curr_limit &
-                                       SD_MAX_CURRENT_200)
-                               current_limit = SD_SET_CURRENT_LIMIT_200;
-               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
-                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
-                               current_limit = SD_SET_CURRENT_LIMIT_400;
-                       else if (card->sw_caps.sd3_curr_limit &
-                                       SD_MAX_CURRENT_200)
-                               current_limit = SD_SET_CURRENT_LIMIT_200;
-               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
-                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
-                               current_limit = SD_SET_CURRENT_LIMIT_200;
-               }
-       } else
+       if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) &&
+           (card->sd_bus_speed != UHS_SDR104_BUS_SPEED) &&
+           (card->sd_bus_speed != UHS_DDR50_BUS_SPEED))
+               return 0;
+
+       /*
+        * Host has different current capabilities when operating at
+        * different voltages, so find out its max current first.
+        */
+       max_current = sd_get_host_max_current(card->host);
+
+       /*
+        * We only check host's capability here, if we set a limit that is
+        * higher than the card's maximum current, the card will be using its
+        * maximum current, e.g. if the card's maximum current is 300ma, and
+        * when we set current limit to 200ma, the card will draw 200ma, and
+        * when we set current limit to 400/600/800ma, the card will draw its
+        * maximum 300ma from the host.
+        */
+       if (max_current >= 800)
+               current_limit = SD_SET_CURRENT_LIMIT_800;
+       else if (max_current >= 600)
+               current_limit = SD_SET_CURRENT_LIMIT_600;
+       else if (max_current >= 400)
+               current_limit = SD_SET_CURRENT_LIMIT_400;
+       else if (max_current >= 200)
                current_limit = SD_SET_CURRENT_LIMIT_200;
 
-       err = mmc_sd_switch(card, 1, 3, current_limit, status);
-       if (err)
-               return err;
+       if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
+               err = mmc_sd_switch(card, 1, 3, current_limit, status);
+               if (err)
+                       return err;
 
-       if (((status[15] >> 4) & 0x0F) != current_limit)
-               pr_warning("%s: Problem setting current limit!\n",
-                       mmc_hostname(card->host));
+               if (((status[15] >> 4) & 0x0F) != current_limit)
+                       pr_warning("%s: Problem setting current limit!\n",
+                               mmc_hostname(card->host));
+
+       }
 
        return 0;
 }
@@ -726,6 +712,7 @@ struct device_type sd_type = {
 int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
 {
        int err;
+       u32 max_current;
 
        /*
         * Since we're changing the OCR value, we seem to
@@ -753,9 +740,12 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
            MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
                ocr |= SD_OCR_S18R;
 
-       /* If the host can supply more than 150mA, XPC should be set to 1. */
-       if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
-           MMC_CAP_SET_XPC_180))
+       /*
+        * If the host can supply more than 150mA at current voltage,
+        * XPC should be set to 1.
+        */
+       max_current = sd_get_host_max_current(host);
+       if (max_current > 150)
                ocr |= SD_OCR_XPC;
 
 try_again:
@@ -911,9 +901,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
-       /* The initialization should be done at 3.3 V I/O voltage. */
-       mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
        err = mmc_sd_get_cid(host, ocr, cid, &rocr);
        if (err)
                return err;
index 41c5fd8848f4d72c171d9e001b2171607e13eb83..d4619e2ec030bcf878dee7a0d43425046d52c2fe 100644 (file)
@@ -591,9 +591,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
         * Inform the card of the voltage
         */
        if (!powered_resume) {
-               /* The initialization should be done at 3.3 V I/O voltage. */
-               mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
                err = mmc_send_io_op_cond(host, host->ocr, &ocr);
                if (err)
                        goto err;
@@ -1006,10 +1003,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
         * restore the correct voltage setting of the card.
         */
 
-       /* The initialization should be done at 3.3 V I/O voltage. */
-       if (!mmc_card_keep_power(host))
-               mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
        sdio_reset(host);
        mmc_go_idle(host);
        mmc_send_if_cond(host, host->ocr_avail);
index f1c7ed8f4d85a2a58b41c7b44d7899f115edaa02..8e94e555b788d4bc56364c488f1af0894e4db50a 100644 (file)
@@ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
 
                        if (ret == -ENOENT) {
                                /* warn about unknown tuples */
-                               pr_warning("%s: queuing unknown"
+                               pr_warn_ratelimited("%s: queuing unknown"
                                       " CIS tuple 0x%02x (%u bytes)\n",
                                       mmc_hostname(card->host),
                                       tpl_code, tpl_link);
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
new file mode 100644 (file)
index 0000000..0582429
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Generic GPIO card-detect helper
+ *
+ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+struct mmc_gpio {
+       int ro_gpio;
+       int cd_gpio;
+       char *ro_label;
+       char cd_label[0];
+};
+
+static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
+{
+       /* Schedule a card detection after a debounce timeout */
+       mmc_detect_change(dev_id, msecs_to_jiffies(100));
+       return IRQ_HANDLED;
+}
+
+static int mmc_gpio_alloc(struct mmc_host *host)
+{
+       size_t len = strlen(dev_name(host->parent)) + 4;
+       struct mmc_gpio *ctx;
+
+       mutex_lock(&host->slot.lock);
+
+       ctx = host->slot.handler_priv;
+       if (!ctx) {
+               /*
+                * devm_kzalloc() can be called after device_initialize(), even
+                * before device_add(), i.e., between mmc_alloc_host() and
+                * mmc_add_host()
+                */
+               ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len,
+                                  GFP_KERNEL);
+               if (ctx) {
+                       ctx->ro_label = ctx->cd_label + len;
+                       snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
+                       snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
+                       ctx->cd_gpio = -EINVAL;
+                       ctx->ro_gpio = -EINVAL;
+                       host->slot.handler_priv = ctx;
+               }
+       }
+
+       mutex_unlock(&host->slot.lock);
+
+       return ctx ? 0 : -ENOMEM;
+}
+
+int mmc_gpio_get_ro(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+
+       if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+               return -ENOSYS;
+
+       return !gpio_get_value_cansleep(ctx->ro_gpio) ^
+               !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
+}
+EXPORT_SYMBOL(mmc_gpio_get_ro);
+
+int mmc_gpio_get_cd(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+
+       if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+               return -ENOSYS;
+
+       return !gpio_get_value_cansleep(ctx->cd_gpio) ^
+               !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+}
+EXPORT_SYMBOL(mmc_gpio_get_cd);
+
+int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
+{
+       struct mmc_gpio *ctx;
+       int ret;
+
+       if (!gpio_is_valid(gpio))
+               return -EINVAL;
+
+       ret = mmc_gpio_alloc(host);
+       if (ret < 0)
+               return ret;
+
+       ctx = host->slot.handler_priv;
+
+       return gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label);
+}
+EXPORT_SYMBOL(mmc_gpio_request_ro);
+
+int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
+{
+       struct mmc_gpio *ctx;
+       int irq = gpio_to_irq(gpio);
+       int ret;
+
+       ret = mmc_gpio_alloc(host);
+       if (ret < 0)
+               return ret;
+
+       ctx = host->slot.handler_priv;
+
+       ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
+       if (ret < 0)
+               /*
+                * don't bother freeing memory. It might still get used by other
+                * slot functions, in any case it will be freed, when the device
+                * is destroyed.
+                */
+               return ret;
+
+       /*
+        * Even if gpio_to_irq() returns a valid IRQ number, the platform might
+        * still prefer to poll, e.g., because that IRQ number is already used
+        * by another unit and cannot be shared.
+        */
+       if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
+               irq = -EINVAL;
+
+       if (irq >= 0) {
+               ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       ctx->cd_label, host);
+               if (ret < 0)
+                       irq = ret;
+       }
+
+       host->slot.cd_irq = irq;
+
+       if (irq < 0)
+               host->caps |= MMC_CAP_NEEDS_POLL;
+
+       ctx->cd_gpio = gpio;
+
+       return 0;
+}
+EXPORT_SYMBOL(mmc_gpio_request_cd);
+
+void mmc_gpio_free_ro(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+       int gpio;
+
+       if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+               return;
+
+       gpio = ctx->ro_gpio;
+       ctx->ro_gpio = -EINVAL;
+
+       gpio_free(gpio);
+}
+EXPORT_SYMBOL(mmc_gpio_free_ro);
+
+void mmc_gpio_free_cd(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+       int gpio;
+
+       if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+               return;
+
+       if (host->slot.cd_irq >= 0) {
+               free_irq(host->slot.cd_irq, host);
+               host->slot.cd_irq = -EINVAL;
+       }
+
+       gpio = ctx->cd_gpio;
+       ctx->cd_gpio = -EINVAL;
+
+       gpio_free(gpio);
+}
+EXPORT_SYMBOL(mmc_gpio_free_cd);
index f2c115e064387715a3c2f2cf796c5ae8b70bddd0..322412cec4eeb8ca6970d2d12f37c7c83bbba42e 100644 (file)
@@ -391,11 +391,17 @@ static int atmci_regs_show(struct seq_file *s, void *v)
        clk_disable(host->mck);
        spin_unlock_bh(&host->lock);
 
-       seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
+       seq_printf(s, "MR:\t0x%08x%s%s ",
                        buf[ATMCI_MR / 4],
                        buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
-                       buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "",
-                       buf[ATMCI_MR / 4] & 0xff);
+                       buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "");
+       if (host->caps.has_odd_clk_div)
+               seq_printf(s, "{CLKDIV,CLKODD}=%u\n",
+                               ((buf[ATMCI_MR / 4] & 0xff) << 1)
+                               | ((buf[ATMCI_MR / 4] >> 16) & 1));
+       else
+               seq_printf(s, "CLKDIV=%u\n",
+                               (buf[ATMCI_MR / 4] & 0xff));
        seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
        seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
        seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
@@ -1685,7 +1691,6 @@ static void atmci_tasklet_func(unsigned long priv)
 
                        dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
                        host->cmd = NULL;
-                       host->data = NULL;
                        data->bytes_xfered = data->blocks * data->blksz;
                        data->error = 0;
                        atmci_command_complete(host, mrq->stop);
@@ -1699,6 +1704,7 @@ static void atmci_tasklet_func(unsigned long priv)
                                atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
                                state = STATE_WAITING_NOTBUSY;
                        }
+                       host->data = NULL;
                        break;
 
                case STATE_END_REQUEST:
index 1ca5e72ceb651e84544a8cc451698ea54de6aafd..72dc3cde646d063513f3a55fc8ba0ec74197261b 100644 (file)
@@ -405,11 +405,23 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
 static int dw_mci_idmac_init(struct dw_mci *host)
 {
        struct idmac_desc *p;
-       int i;
+       int i, dma_support;
 
        /* Number of descriptors in the ring buffer */
        host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
 
+       /* Check if Hardware Configuration Register has support for DMA */
+       dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
+
+       if (!dma_support || dma_support > 2) {
+               dev_err(&host->dev,
+                       "Host Controller does not support IDMA Tx.\n");
+               host->dma_ops = NULL;
+               return -ENODEV;
+       }
+
+       dev_info(&host->dev, "Using internal DMA controller.\n");
+
        /* Forward link the descriptor list */
        for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
                p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
@@ -1876,7 +1888,6 @@ static void dw_mci_init_dma(struct dw_mci *host)
        /* Determine which DMA interface to use */
 #ifdef CONFIG_MMC_DW_IDMAC
        host->dma_ops = &dw_mci_idmac_ops;
-       dev_info(&host->dev, "Using internal DMA controller.\n");
 #endif
 
        if (!host->dma_ops)
@@ -2175,7 +2186,7 @@ int dw_mci_resume(struct dw_mci *host)
                return ret;
        }
 
-       if (host->dma_ops->init)
+       if (host->use_dma && host->dma_ops->init)
                host->dma_ops->init(host);
 
        /* Restore the old value at FIFOTH register */
index 277161d279b8048600e6b7333d05d9c022562886..a51f9309ffbb1e49947939fb60d6c6dcc8e3be93 100644 (file)
@@ -164,16 +164,23 @@ struct mxs_mmc_host {
        spinlock_t                      lock;
        int                             sdio_irq_en;
        int                             wp_gpio;
+       bool                            wp_inverted;
 };
 
 static int mxs_mmc_get_ro(struct mmc_host *mmc)
 {
        struct mxs_mmc_host *host = mmc_priv(mmc);
+       int ret;
 
        if (!gpio_is_valid(host->wp_gpio))
                return -EINVAL;
 
-       return gpio_get_value(host->wp_gpio);
+       ret = gpio_get_value(host->wp_gpio);
+
+       if (host->wp_inverted)
+               ret = !ret;
+
+       return ret;
 }
 
 static int mxs_mmc_get_cd(struct mmc_host *mmc)
@@ -707,6 +714,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        struct pinctrl *pinctrl;
        int ret = 0, irq_err, irq_dma;
        dma_cap_mask_t mask;
+       struct regulator *reg_vmmc;
+       enum of_gpio_flags flags;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -747,6 +756,16 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        host->mmc = mmc;
        host->sdio_irq_en = 0;
 
+       reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc");
+       if (!IS_ERR(reg_vmmc)) {
+               ret = regulator_enable(reg_vmmc);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Failed to enable vmmc regulator: %d\n", ret);
+                       goto out_mmc_free;
+               }
+       }
+
        pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
        if (IS_ERR(pinctrl)) {
                ret = PTR_ERR(pinctrl);
@@ -785,7 +804,10 @@ static int mxs_mmc_probe(struct platform_device *pdev)
                        mmc->caps |= MMC_CAP_4_BIT_DATA;
                else if (bus_width == 8)
                        mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
-               host->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
+               host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0,
+                                                       &flags);
+               if (flags & OF_GPIO_ACTIVE_LOW)
+                       host->wp_inverted = 1;
        } else {
                if (pdata->flags & SLOTF_8_BIT_CAPABLE)
                        mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
index 389a3eedfc24505de5034e7d842f6e5678e4bc25..bc28627af66b961372f0f38cc0bbe61d621cc99a 100644 (file)
@@ -1089,7 +1089,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
        /* Disable the clocks */
        pm_runtime_put_sync(host->dev);
        if (host->dbclk)
-               clk_disable(host->dbclk);
+               clk_disable_unprepare(host->dbclk);
 
        /* Turn the power off */
        ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
@@ -1100,7 +1100,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
                                               vdd);
        pm_runtime_get_sync(host->dev);
        if (host->dbclk)
-               clk_enable(host->dbclk);
+               clk_prepare_enable(host->dbclk);
 
        if (ret != 0)
                goto err;
@@ -1899,7 +1899,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
        if (IS_ERR(host->dbclk)) {
                dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");
                host->dbclk = NULL;
-       } else if (clk_enable(host->dbclk) != 0) {
+       } else if (clk_prepare_enable(host->dbclk) != 0) {
                dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
                clk_put(host->dbclk);
                host->dbclk = NULL;
@@ -1931,6 +1931,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
        if (!res) {
                dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
+               ret = -ENXIO;
                goto err_irq;
        }
        host->dma_line_tx = res->start;
@@ -1938,6 +1939,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
        if (!res) {
                dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
+               ret = -ENXIO;
                goto err_irq;
        }
        host->dma_line_rx = res->start;
@@ -2023,7 +2025,7 @@ err_irq:
        pm_runtime_disable(host->dev);
        clk_put(host->fclk);
        if (host->dbclk) {
-               clk_disable(host->dbclk);
+               clk_disable_unprepare(host->dbclk);
                clk_put(host->dbclk);
        }
 err1:
@@ -2058,7 +2060,7 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
        pm_runtime_disable(host->dev);
        clk_put(host->fclk);
        if (host->dbclk) {
-               clk_disable(host->dbclk);
+               clk_disable_unprepare(host->dbclk);
                clk_put(host->dbclk);
        }
 
@@ -2116,7 +2118,7 @@ static int omap_hsmmc_suspend(struct device *dev)
        }
 
        if (host->dbclk)
-               clk_disable(host->dbclk);
+               clk_disable_unprepare(host->dbclk);
 err:
        pm_runtime_put_sync(host->dev);
        return ret;
@@ -2137,7 +2139,7 @@ static int omap_hsmmc_resume(struct device *dev)
        pm_runtime_get_sync(host->dev);
 
        if (host->dbclk)
-               clk_enable(host->dbclk);
+               clk_prepare_enable(host->dbclk);
 
        if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
                omap_hsmmc_conf_bus_power(host);
index c3622a69f432b34e63f218ad1e003ea48bc69922..bd5a5cce122c7eb199a67cad4098175ff6a9b351 100644 (file)
@@ -26,7 +26,6 @@
 #include <mach/dma.h>
 
 #include <mach/regs-sdi.h>
-#include <mach/regs-gpio.h>
 
 #include <plat/mci.h>
 
@@ -1237,12 +1236,9 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        switch (ios->power_mode) {
        case MMC_POWER_ON:
        case MMC_POWER_UP:
-               s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);
-               s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);
-               s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);
-               s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
-               s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);
-               s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3);
+               /* Configure GPE5...GPE10 pins in SD mode */
+               s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2),
+                                     S3C_GPIO_PULL_NONE);
 
                if (host->pdata->set_power)
                        host->pdata->set_power(ios->power_mode, ios->vdd);
index 177f697b5835529aa3a4079966229c751f7bc428..a6e53a1ebb0888639a49d75c72f562f45b48e4f1 100644 (file)
  */
 
 #include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/mmc/host.h>
 
 #include "sdhci-pltfm.h"
 
+struct sdhci_dove_priv {
+       struct clk *clk;
+};
+
 static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
 {
        u16 ret;
@@ -66,16 +72,57 @@ static struct sdhci_pltfm_data sdhci_dove_pdata = {
        .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
                  SDHCI_QUIRK_NO_BUSY_IRQ |
                  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
-                 SDHCI_QUIRK_FORCE_DMA,
+                 SDHCI_QUIRK_FORCE_DMA |
+                 SDHCI_QUIRK_NO_HISPD_BIT,
 };
 
 static int __devinit sdhci_dove_probe(struct platform_device *pdev)
 {
-       return sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
+       struct sdhci_host *host;
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_dove_priv *priv;
+       int ret;
+
+       ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
+       if (ret)
+               goto sdhci_dove_register_fail;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv),
+                           GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "unable to allocate private data");
+               ret = -ENOMEM;
+               goto sdhci_dove_allocate_fail;
+       }
+
+       host = platform_get_drvdata(pdev);
+       pltfm_host = sdhci_priv(host);
+       pltfm_host->priv = priv;
+
+       priv->clk = clk_get(&pdev->dev, NULL);
+       if (!IS_ERR(priv->clk))
+               clk_prepare_enable(priv->clk);
+       return 0;
+
+sdhci_dove_allocate_fail:
+       sdhci_pltfm_unregister(pdev);
+sdhci_dove_register_fail:
+       return ret;
 }
 
 static int __devexit sdhci_dove_remove(struct platform_device *pdev)
 {
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_dove_priv *priv = pltfm_host->priv;
+
+       if (priv->clk) {
+               if (!IS_ERR(priv->clk)) {
+                       clk_disable_unprepare(priv->clk);
+                       clk_put(priv->clk);
+               }
+               devm_kfree(&pdev->dev, priv->clk);
+       }
        return sdhci_pltfm_unregister(pdev);
 }
 
index ebbe984e5d002c5dfe98d7215309676a8a183789..e23f8134591c7f5a080f73ffcacbf6fccb63516e 100644 (file)
@@ -299,6 +299,8 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
 
 static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
 {
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct pltfm_imx_data *imx_data = pltfm_host->priv;
        u32 new_val;
 
        switch (reg) {
@@ -315,8 +317,11 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
                                SDHCI_CTRL_D3CD);
                /* ensure the endianess */
                new_val |= ESDHC_HOST_CONTROL_LE;
-               /* DMA mode bits are shifted */
-               new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+               /* bits 8&9 are reserved on mx25 */
+               if (!is_imx25_esdhc(imx_data)) {
+                       /* DMA mode bits are shifted */
+                       new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+               }
 
                esdhc_clrset_le(host, 0xffff, new_val, reg);
                return;
index 69ef0beae104f3a83d4a36277b129e20ba5db207..504da715a41ae30f3e5670ff305801167ee60935 100644 (file)
@@ -157,6 +157,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = {
 static const struct sdhci_pci_fixes sdhci_cafe = {
        .quirks         = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
                          SDHCI_QUIRK_NO_BUSY_IRQ |
+                         SDHCI_QUIRK_BROKEN_CARD_DETECTION |
                          SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
index dbb75bfbcffb3e181f6d0af195209e5187c3b210..b6ee8857e226fc163d53c1a66d52eda26121735d 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/mmc/host.h>
 #include <linux/platform_data/pxa_sdhci.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
@@ -121,6 +124,48 @@ static struct sdhci_ops pxav2_sdhci_ops = {
        .platform_8bit_width = pxav2_mmc_set_width,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_pxav2_of_match[] = {
+       {
+               .compatible = "mrvl,pxav2-mmc",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sdhci_pxav2_of_match);
+
+static struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
+{
+       struct sdhci_pxa_platdata *pdata;
+       struct device_node *np = dev->of_node;
+       u32 bus_width;
+       u32 clk_delay_cycles;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       if (of_find_property(np, "non-removable", NULL))
+               pdata->flags |= PXA_FLAG_CARD_PERMANENT;
+
+       of_property_read_u32(np, "bus-width", &bus_width);
+       if (bus_width == 8)
+               pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
+
+       of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
+       if (clk_delay_cycles > 0) {
+               pdata->clk_delay_sel = 1;
+               pdata->clk_delay_cycles = clk_delay_cycles;
+       }
+
+       return pdata;
+}
+#else
+static inline struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
 {
        struct sdhci_pltfm_host *pltfm_host;
@@ -128,6 +173,8 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct sdhci_host *host = NULL;
        struct sdhci_pxa *pxa = NULL;
+       const struct of_device_id *match;
+
        int ret;
        struct clk *clk;
 
@@ -156,6 +203,10 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
                | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
                | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
 
+       match = of_match_device(of_match_ptr(sdhci_pxav2_of_match), &pdev->dev);
+       if (match) {
+               pdata = pxav2_get_mmc_pdata(dev);
+       }
        if (pdata) {
                if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
                        /* on-chip device */
@@ -218,6 +269,9 @@ static struct platform_driver sdhci_pxav2_driver = {
        .driver         = {
                .name   = "sdhci-pxav2",
                .owner  = THIS_MODULE,
+#ifdef CONFIG_OF
+               .of_match_table = sdhci_pxav2_of_match,
+#endif
                .pm     = SDHCI_PLTFM_PMOPS,
        },
        .probe          = sdhci_pxav2_probe,
index f29695683556df8f7c01ad6f145a9fc36583e410..07fe3834fe0b224119d0591672de48949dd18105 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 
@@ -164,6 +167,46 @@ static struct sdhci_ops pxav3_sdhci_ops = {
        .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id sdhci_pxav3_of_match[] = {
+       {
+               .compatible = "mrvl,pxav3-mmc",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
+
+static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
+{
+       struct sdhci_pxa_platdata *pdata;
+       struct device_node *np = dev->of_node;
+       u32 bus_width;
+       u32 clk_delay_cycles;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       if (of_find_property(np, "non-removable", NULL))
+               pdata->flags |= PXA_FLAG_CARD_PERMANENT;
+
+       of_property_read_u32(np, "bus-width", &bus_width);
+       if (bus_width == 8)
+               pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
+
+       of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
+       if (clk_delay_cycles > 0)
+               pdata->clk_delay_cycles = clk_delay_cycles;
+
+       return pdata;
+}
+#else
+static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
 {
        struct sdhci_pltfm_host *pltfm_host;
@@ -171,6 +214,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct sdhci_host *host = NULL;
        struct sdhci_pxa *pxa = NULL;
+       const struct of_device_id *match;
+
        int ret;
        struct clk *clk;
 
@@ -202,6 +247,10 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        /* enable 1/8V DDR capable */
        host->mmc->caps |= MMC_CAP_1_8V_DDR;
 
+       match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
+       if (match)
+               pdata = pxav3_get_mmc_pdata(dev);
+
        if (pdata) {
                if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
                        /* on-chip device */
@@ -263,6 +312,9 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
 static struct platform_driver sdhci_pxav3_driver = {
        .driver         = {
                .name   = "sdhci-pxav3",
+#ifdef CONFIG_OF
+               .of_match_table = sdhci_pxav3_of_match,
+#endif
                .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
        },
index b38d8a78f6a033ad28c6b50d30309c2c48ff03c8..6e5338a071cead5569dce9ccdd13d2610534650f 100644 (file)
@@ -223,6 +223,7 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
 {
        struct tegra_sdhci_platform_data *plat;
        struct device_node *np = pdev->dev.of_node;
+       u32 bus_width;
 
        if (!np)
                return NULL;
@@ -236,7 +237,9 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
        plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
        plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
        plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
-       if (of_find_property(np, "support-8bit", NULL))
+
+       if (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
+           bus_width == 8)
                plat->is_8bit = 1;
 
        return plat;
index f4b8b4db3a9acd8ccc1c3fdf32c18efc2a8bc88d..9a11dc39921c06ebdf67a3ed602fbba79cc38b89 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
 
 #include "sdhci.h"
 
@@ -244,6 +245,19 @@ static void sdhci_init(struct sdhci_host *host, int soft)
 static void sdhci_reinit(struct sdhci_host *host)
 {
        sdhci_init(host, 0);
+       /*
+        * Retuning stuffs are affected by different cards inserted and only
+        * applicable to UHS-I cards. So reset these fields to their initial
+        * value when card is removed.
+        */
+       if (host->flags & SDHCI_USING_RETUNING_TIMER) {
+               host->flags &= ~SDHCI_USING_RETUNING_TIMER;
+
+               del_timer_sync(&host->tuning_timer);
+               host->flags &= ~SDHCI_NEEDS_RETUNING;
+               host->mmc->max_blk_count =
+                       (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
+       }
        sdhci_enable_card_detection(host);
 }
 
@@ -1245,6 +1259,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        struct sdhci_host *host;
        bool present;
        unsigned long flags;
+       u32 tuning_opcode;
 
        host = mmc_priv(mmc);
 
@@ -1292,8 +1307,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                 */
                if ((host->flags & SDHCI_NEEDS_RETUNING) &&
                    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
+                       /* eMMC uses cmd21 while sd and sdio use cmd19 */
+                       tuning_opcode = mmc->card->type == MMC_TYPE_MMC ?
+                               MMC_SEND_TUNING_BLOCK_HS200 :
+                               MMC_SEND_TUNING_BLOCK;
                        spin_unlock_irqrestore(&host->lock, flags);
-                       sdhci_execute_tuning(mmc, mrq->cmd->opcode);
+                       sdhci_execute_tuning(mmc, tuning_opcode);
                        spin_lock_irqsave(&host->lock, flags);
 
                        /* Restore original mmc_request structure */
@@ -1663,11 +1682,15 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
                pwr &= ~SDHCI_POWER_ON;
                sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+               if (host->vmmc)
+                       regulator_disable(host->vmmc);
 
                /* Wait for 1ms as per the spec */
                usleep_range(1000, 1500);
                pwr |= SDHCI_POWER_ON;
                sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+               if (host->vmmc)
+                       regulator_enable(host->vmmc);
 
                pr_info(DRIVER_NAME ": Switching to 1.8V signalling "
                        "voltage failed, retrying with S18R set to 0\n");
@@ -1855,6 +1878,7 @@ out:
         */
        if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
            (host->tuning_mode == SDHCI_TUNING_MODE_1)) {
+               host->flags |= SDHCI_USING_RETUNING_TIMER;
                mod_timer(&host->tuning_timer, jiffies +
                        host->tuning_count * HZ);
                /* Tuning mode 1 limits the maximum data length to 4MB */
@@ -1872,10 +1896,10 @@ out:
         * try tuning again at a later time, when the re-tuning timer expires.
         * So for these controllers, we return 0. Since there might be other
         * controllers who do not have this capability, we return error for
-        * them.
+        * them. SDHCI_USING_RETUNING_TIMER means the host is currently using
+        * a retuning timer to do the retuning for the card.
         */
-       if (err && host->tuning_count &&
-           host->tuning_mode == SDHCI_TUNING_MODE_1)
+       if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
                err = 0;
 
        sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
@@ -2382,7 +2406,6 @@ out:
 int sdhci_suspend_host(struct sdhci_host *host)
 {
        int ret;
-       bool has_tuning_timer;
 
        if (host->ops->platform_suspend)
                host->ops->platform_suspend(host);
@@ -2390,16 +2413,14 @@ int sdhci_suspend_host(struct sdhci_host *host)
        sdhci_disable_card_detection(host);
 
        /* Disable tuning since we are suspending */
-       has_tuning_timer = host->version >= SDHCI_SPEC_300 &&
-               host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1;
-       if (has_tuning_timer) {
+       if (host->flags & SDHCI_USING_RETUNING_TIMER) {
                del_timer_sync(&host->tuning_timer);
                host->flags &= ~SDHCI_NEEDS_RETUNING;
        }
 
        ret = mmc_suspend_host(host->mmc);
        if (ret) {
-               if (has_tuning_timer) {
+               if (host->flags & SDHCI_USING_RETUNING_TIMER) {
                        host->flags |= SDHCI_NEEDS_RETUNING;
                        mod_timer(&host->tuning_timer, jiffies +
                                        host->tuning_count * HZ);
@@ -2450,8 +2471,7 @@ int sdhci_resume_host(struct sdhci_host *host)
                host->ops->platform_resume(host);
 
        /* Set the re-tuning expiration flag */
-       if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
-           (host->tuning_mode == SDHCI_TUNING_MODE_1))
+       if (host->flags & SDHCI_USING_RETUNING_TIMER)
                host->flags |= SDHCI_NEEDS_RETUNING;
 
        return ret;
@@ -2490,8 +2510,7 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        int ret = 0;
 
        /* Disable tuning since we are suspending */
-       if (host->version >= SDHCI_SPEC_300 &&
-           host->tuning_mode == SDHCI_TUNING_MODE_1) {
+       if (host->flags & SDHCI_USING_RETUNING_TIMER) {
                del_timer_sync(&host->tuning_timer);
                host->flags &= ~SDHCI_NEEDS_RETUNING;
        }
@@ -2532,8 +2551,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
                sdhci_do_enable_preset_value(host, true);
 
        /* Set the re-tuning expiration flag */
-       if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
-           (host->tuning_mode == SDHCI_TUNING_MODE_1))
+       if (host->flags & SDHCI_USING_RETUNING_TIMER)
                host->flags |= SDHCI_NEEDS_RETUNING;
 
        spin_lock_irqsave(&host->lock, flags);
@@ -2584,7 +2602,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
 int sdhci_add_host(struct sdhci_host *host)
 {
        struct mmc_host *mmc;
-       u32 caps[2];
+       u32 caps[2] = {0, 0};
        u32 max_current_caps;
        unsigned int ocr_avail;
        int ret;
@@ -2614,8 +2632,10 @@ int sdhci_add_host(struct sdhci_host *host)
        caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
                sdhci_readl(host, SDHCI_CAPABILITIES);
 
-       caps[1] = (host->version >= SDHCI_SPEC_300) ?
-               sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
+       if (host->version >= SDHCI_SPEC_300)
+               caps[1] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ?
+                       host->caps1 :
+                       sdhci_readl(host, SDHCI_CAPABILITIES_1);
 
        if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
                host->flags |= SDHCI_USE_SDMA;
@@ -2779,7 +2799,7 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
-           mmc_card_is_removable(mmc))
+           !(host->mmc->caps & MMC_CAP_NONREMOVABLE))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
@@ -2837,6 +2857,30 @@ int sdhci_add_host(struct sdhci_host *host)
                             SDHCI_RETUNING_MODE_SHIFT;
 
        ocr_avail = 0;
+
+       host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+       if (IS_ERR(host->vmmc)) {
+               pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
+               host->vmmc = NULL;
+       }
+
+#ifdef CONFIG_REGULATOR
+       if (host->vmmc) {
+               ret = regulator_is_supported_voltage(host->vmmc, 3300000,
+                       3300000);
+               if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
+                       caps[0] &= ~SDHCI_CAN_VDD_330;
+               ret = regulator_is_supported_voltage(host->vmmc, 3000000,
+                       3000000);
+               if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
+                       caps[0] &= ~SDHCI_CAN_VDD_300;
+               ret = regulator_is_supported_voltage(host->vmmc, 1800000,
+                       1800000);
+               if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
+                       caps[0] &= ~SDHCI_CAN_VDD_180;
+       }
+#endif /* CONFIG_REGULATOR */
+
        /*
         * According to SD Host Controller spec v3.00, if the Host System
         * can afford more than 150mA, Host Driver should set XPC to 1. Also
@@ -2845,55 +2889,45 @@ int sdhci_add_host(struct sdhci_host *host)
         * value.
         */
        max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
+       if (!max_current_caps && host->vmmc) {
+               u32 curr = regulator_get_current_limit(host->vmmc);
+               if (curr > 0) {
+
+                       /* convert to SDHCI_MAX_CURRENT format */
+                       curr = curr/1000;  /* convert to mA */
+                       curr = curr/SDHCI_MAX_CURRENT_MULTIPLIER;
+
+                       curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
+                       max_current_caps =
+                               (curr << SDHCI_MAX_CURRENT_330_SHIFT) |
+                               (curr << SDHCI_MAX_CURRENT_300_SHIFT) |
+                               (curr << SDHCI_MAX_CURRENT_180_SHIFT);
+               }
+       }
 
        if (caps[0] & SDHCI_CAN_VDD_330) {
-               int max_current_330;
-
                ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
 
-               max_current_330 = ((max_current_caps &
+               mmc->max_current_330 = ((max_current_caps &
                                   SDHCI_MAX_CURRENT_330_MASK) >>
                                   SDHCI_MAX_CURRENT_330_SHIFT) *
                                   SDHCI_MAX_CURRENT_MULTIPLIER;
-
-               if (max_current_330 > 150)
-                       mmc->caps |= MMC_CAP_SET_XPC_330;
        }
        if (caps[0] & SDHCI_CAN_VDD_300) {
-               int max_current_300;
-
                ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
 
-               max_current_300 = ((max_current_caps &
+               mmc->max_current_300 = ((max_current_caps &
                                   SDHCI_MAX_CURRENT_300_MASK) >>
                                   SDHCI_MAX_CURRENT_300_SHIFT) *
                                   SDHCI_MAX_CURRENT_MULTIPLIER;
-
-               if (max_current_300 > 150)
-                       mmc->caps |= MMC_CAP_SET_XPC_300;
        }
        if (caps[0] & SDHCI_CAN_VDD_180) {
-               int max_current_180;
-
                ocr_avail |= MMC_VDD_165_195;
 
-               max_current_180 = ((max_current_caps &
+               mmc->max_current_180 = ((max_current_caps &
                                   SDHCI_MAX_CURRENT_180_MASK) >>
                                   SDHCI_MAX_CURRENT_180_SHIFT) *
                                   SDHCI_MAX_CURRENT_MULTIPLIER;
-
-               if (max_current_180 > 150)
-                       mmc->caps |= MMC_CAP_SET_XPC_180;
-
-               /* Maximum current capabilities of the host at 1.8V */
-               if (max_current_180 >= 800)
-                       mmc->caps |= MMC_CAP_MAX_CURRENT_800;
-               else if (max_current_180 >= 600)
-                       mmc->caps |= MMC_CAP_MAX_CURRENT_600;
-               else if (max_current_180 >= 400)
-                       mmc->caps |= MMC_CAP_MAX_CURRENT_400;
-               else
-                       mmc->caps |= MMC_CAP_MAX_CURRENT_200;
        }
 
        mmc->ocr_avail = ocr_avail;
@@ -2992,13 +3026,10 @@ int sdhci_add_host(struct sdhci_host *host)
 
        ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
                mmc_hostname(mmc), host);
-       if (ret)
+       if (ret) {
+               pr_err("%s: Failed to request IRQ %d: %d\n",
+                      mmc_hostname(mmc), host->irq, ret);
                goto untasklet;
-
-       host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
-       if (IS_ERR(host->vmmc)) {
-               pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
-               host->vmmc = NULL;
        }
 
        sdhci_init(host, 0);
@@ -3016,8 +3047,11 @@ int sdhci_add_host(struct sdhci_host *host)
        host->led.brightness_set = sdhci_led_control;
 
        ret = led_classdev_register(mmc_dev(mmc), &host->led);
-       if (ret)
+       if (ret) {
+               pr_err("%s: Failed to register LED device: %d\n",
+                      mmc_hostname(mmc), ret);
                goto reset;
+       }
 #endif
 
        mmiowb();
@@ -3081,8 +3115,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
-       if (host->version >= SDHCI_SPEC_300)
-               del_timer_sync(&host->tuning_timer);
 
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
index f761f23d2a28ccb287e1da22b2433478833b82f1..97653ea8942ba82393f47b6291942e28c2435204 100644 (file)
 #define SDHCI_CAPABILITIES_1   0x44
 
 #define SDHCI_MAX_CURRENT              0x48
+#define  SDHCI_MAX_CURRENT_LIMIT       0xFF
 #define  SDHCI_MAX_CURRENT_330_MASK    0x0000FF
 #define  SDHCI_MAX_CURRENT_330_SHIFT   0
 #define  SDHCI_MAX_CURRENT_300_MASK    0x00FF00
index 724b35e85a265f70faa11fe8f603931a687f04af..b2af7136cd27445d33225e36d5314005dcfb39b6 100644 (file)
@@ -54,6 +54,8 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/mod_devicetable.h>
 #include <linux/pagemap.h>
 #include <linux/platform_device.h>
 #include <linux/pm_qos.h>
@@ -384,6 +386,9 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
        struct sh_dmae_slave *tx, *rx;
        host->dma_active = false;
 
+       if (!pdata)
+               return;
+
        /* We can only either use DMA for both Tx and Rx or not use it at all */
        if (pdata->dma) {
                dev_warn(&host->pd->dev,
@@ -444,13 +449,14 @@ static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
 static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
 {
        struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+       bool sup_pclk = p ? p->sup_pclk : false;
 
        sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
        sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
 
        if (!clk)
                return;
-       if (p->sup_pclk && clk == host->clk)
+       if (sup_pclk && clk == host->clk)
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
        else
                sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
@@ -892,21 +898,15 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        switch (mrq->cmd->opcode) {
        /* MMCIF does not support SD/SDIO command */
-       case SD_IO_SEND_OP_COND:
+       case MMC_SLEEP_AWAKE: /* = SD_IO_SEND_OP_COND (5) */
+       case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
+               if ((mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_BCR)
+                       break;
        case MMC_APP_CMD:
                host->state = STATE_IDLE;
                mrq->cmd->error = -ETIMEDOUT;
                mmc_request_done(mmc, mrq);
                return;
-       case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
-               if (!mrq->data) {
-                       /* send_if_cond cmd (not support) */
-                       host->state = STATE_IDLE;
-                       mrq->cmd->error = -ETIMEDOUT;
-                       mmc_request_done(mmc, mrq);
-                       return;
-               }
-               break;
        default:
                break;
        }
@@ -916,10 +916,35 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
        sh_mmcif_start_cmd(host, mrq);
 }
 
+static int sh_mmcif_clk_update(struct sh_mmcif_host *host)
+{
+       int ret = clk_enable(host->hclk);
+
+       if (!ret) {
+               host->clk = clk_get_rate(host->hclk);
+               host->mmc->f_max = host->clk / 2;
+               host->mmc->f_min = host->clk / 512;
+       }
+
+       return ret;
+}
+
+static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios)
+{
+       struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data;
+       struct mmc_host *mmc = host->mmc;
+
+       if (pd && pd->set_pwr)
+               pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF);
+       if (!IS_ERR(mmc->supply.vmmc))
+               /* Errors ignored... */
+               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+                                     ios->power_mode ? ios->vdd : 0);
+}
+
 static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct sh_mmcif_host *host = mmc_priv(mmc);
-       struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
        unsigned long flags;
 
        spin_lock_irqsave(&host->lock, flags);
@@ -937,6 +962,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        sh_mmcif_request_dma(host, host->pd->dev.platform_data);
                        host->card_present = true;
                }
+               sh_mmcif_set_power(host, ios);
        } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* clock stop */
                sh_mmcif_clock_control(host, 0);
@@ -948,9 +974,10 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                }
                if (host->power) {
                        pm_runtime_put(&host->pd->dev);
+                       clk_disable(host->hclk);
                        host->power = false;
-                       if (p->down_pwr && ios->power_mode == MMC_POWER_OFF)
-                               p->down_pwr(host->pd);
+                       if (ios->power_mode == MMC_POWER_OFF)
+                               sh_mmcif_set_power(host, ios);
                }
                host->state = STATE_IDLE;
                return;
@@ -958,8 +985,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        if (ios->clock) {
                if (!host->power) {
-                       if (p->set_pwr)
-                               p->set_pwr(host->pd, ios->power_mode);
+                       sh_mmcif_clk_update(host);
                        pm_runtime_get_sync(&host->pd->dev);
                        host->power = true;
                        sh_mmcif_sync_reset(host);
@@ -975,8 +1001,12 @@ static int sh_mmcif_get_cd(struct mmc_host *mmc)
 {
        struct sh_mmcif_host *host = mmc_priv(mmc);
        struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+       int ret = mmc_gpio_get_cd(mmc);
+
+       if (ret >= 0)
+               return ret;
 
-       if (!p->get_cd)
+       if (!p || !p->get_cd)
                return -ENOSYS;
        else
                return p->get_cd(host->pd);
@@ -1242,12 +1272,28 @@ static void mmcif_timeout_work(struct work_struct *work)
        mmc_request_done(host->mmc, mrq);
 }
 
+static void sh_mmcif_init_ocr(struct sh_mmcif_host *host)
+{
+       struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data;
+       struct mmc_host *mmc = host->mmc;
+
+       mmc_regulator_get_supply(mmc);
+
+       if (!pd)
+               return;
+
+       if (!mmc->ocr_avail)
+               mmc->ocr_avail = pd->ocr;
+       else if (pd->ocr)
+               dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
+}
+
 static int __devinit sh_mmcif_probe(struct platform_device *pdev)
 {
        int ret = 0, irq[2];
        struct mmc_host *mmc;
        struct sh_mmcif_host *host;
-       struct sh_mmcif_plat_data *pd;
+       struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
        struct resource *res;
        void __iomem *reg;
        char clk_name[8];
@@ -1268,42 +1314,26 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "ioremap error.\n");
                return -ENOMEM;
        }
-       pd = pdev->dev.platform_data;
-       if (!pd) {
-               dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
-               ret = -ENXIO;
-               goto clean_up;
-       }
+
        mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev);
        if (!mmc) {
                ret = -ENOMEM;
-               goto clean_up;
+               goto ealloch;
        }
        host            = mmc_priv(mmc);
        host->mmc       = mmc;
        host->addr      = reg;
        host->timeout   = 1000;
 
-       snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
-       host->hclk = clk_get(&pdev->dev, clk_name);
-       if (IS_ERR(host->hclk)) {
-               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
-               ret = PTR_ERR(host->hclk);
-               goto clean_up1;
-       }
-       clk_enable(host->hclk);
-       host->clk = clk_get_rate(host->hclk);
        host->pd = pdev;
 
        spin_lock_init(&host->lock);
 
        mmc->ops = &sh_mmcif_ops;
-       mmc->f_max = host->clk / 2;
-       mmc->f_min = host->clk / 512;
-       if (pd->ocr)
-               mmc->ocr_avail = pd->ocr;
+       sh_mmcif_init_ocr(host);
+
        mmc->caps = MMC_CAP_MMC_HIGHSPEED;
-       if (pd->caps)
+       if (pd && pd->caps)
                mmc->caps |= pd->caps;
        mmc->max_segs = 32;
        mmc->max_blk_size = 512;
@@ -1311,34 +1341,52 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size;
        mmc->max_seg_size = mmc->max_req_size;
 
-       sh_mmcif_sync_reset(host);
        platform_set_drvdata(pdev, host);
 
        pm_runtime_enable(&pdev->dev);
        host->power = false;
 
+       snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
+       host->hclk = clk_get(&pdev->dev, clk_name);
+       if (IS_ERR(host->hclk)) {
+               ret = PTR_ERR(host->hclk);
+               dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret);
+               goto eclkget;
+       }
+       ret = sh_mmcif_clk_update(host);
+       if (ret < 0)
+               goto eclkupdate;
+
        ret = pm_runtime_resume(&pdev->dev);
        if (ret < 0)
-               goto clean_up2;
+               goto eresume;
 
        INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
 
+       sh_mmcif_sync_reset(host);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
        ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
-               goto clean_up3;
+               goto ereqirq0;
        }
        ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
-               goto clean_up4;
+               goto ereqirq1;
+       }
+
+       if (pd && pd->use_cd_gpio) {
+               ret = mmc_gpio_request_cd(mmc, pd->cd_gpio);
+               if (ret < 0)
+                       goto erqcd;
        }
 
+       clk_disable(host->hclk);
        ret = mmc_add_host(mmc);
        if (ret < 0)
-               goto clean_up5;
+               goto emmcaddh;
 
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
 
@@ -1347,33 +1395,42 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
                sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
        return ret;
 
-clean_up5:
+emmcaddh:
+       if (pd && pd->use_cd_gpio)
+               mmc_gpio_free_cd(mmc);
+erqcd:
        free_irq(irq[1], host);
-clean_up4:
+ereqirq1:
        free_irq(irq[0], host);
-clean_up3:
+ereqirq0:
        pm_runtime_suspend(&pdev->dev);
-clean_up2:
-       pm_runtime_disable(&pdev->dev);
+eresume:
        clk_disable(host->hclk);
-clean_up1:
+eclkupdate:
+       clk_put(host->hclk);
+eclkget:
+       pm_runtime_disable(&pdev->dev);
        mmc_free_host(mmc);
-clean_up:
-       if (reg)
-               iounmap(reg);
+ealloch:
+       iounmap(reg);
        return ret;
 }
 
 static int __devexit sh_mmcif_remove(struct platform_device *pdev)
 {
        struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+       struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
        int irq[2];
 
        host->dying = true;
+       clk_enable(host->hclk);
        pm_runtime_get_sync(&pdev->dev);
 
        dev_pm_qos_hide_latency_limit(&pdev->dev);
 
+       if (pd && pd->use_cd_gpio)
+               mmc_gpio_free_cd(host->mmc);
+
        mmc_remove_host(host->mmc);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
@@ -1395,9 +1452,9 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, NULL);
 
-       clk_disable(host->hclk);
        mmc_free_host(host->mmc);
        pm_runtime_put_sync(&pdev->dev);
+       clk_disable(host->hclk);
        pm_runtime_disable(&pdev->dev);
 
        return 0;
@@ -1406,24 +1463,18 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int sh_mmcif_suspend(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+       struct sh_mmcif_host *host = dev_get_drvdata(dev);
        int ret = mmc_suspend_host(host->mmc);
 
-       if (!ret) {
+       if (!ret)
                sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-               clk_disable(host->hclk);
-       }
 
        return ret;
 }
 
 static int sh_mmcif_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sh_mmcif_host *host = platform_get_drvdata(pdev);
-
-       clk_enable(host->hclk);
+       struct sh_mmcif_host *host = dev_get_drvdata(dev);
 
        return mmc_resume_host(host->mmc);
 }
@@ -1432,6 +1483,12 @@ static int sh_mmcif_resume(struct device *dev)
 #define sh_mmcif_resume                NULL
 #endif /* CONFIG_PM */
 
+static const struct of_device_id mmcif_of_match[] = {
+       { .compatible = "renesas,sh-mmcif" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mmcif_of_match);
+
 static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
        .suspend = sh_mmcif_suspend,
        .resume = sh_mmcif_resume,
@@ -1443,6 +1500,8 @@ static struct platform_driver sh_mmcif_driver = {
        .driver         = {
                .name   = DRIVER_NAME,
                .pm     = &sh_mmcif_dev_pm_ops,
+               .owner  = THIS_MODULE,
+               .of_match_table = mmcif_of_match,
        },
 };
 
index 934b68e9efc34e50796495ea61a37d2ed598e155..a842939e46555295f32418ac05f96c495d734ea2 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mmc/host.h>
@@ -39,22 +40,39 @@ struct sh_mobile_sdhi {
        struct tmio_mmc_dma dma_priv;
 };
 
+static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
+{
+       struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+       int ret = clk_enable(priv->clk);
+       if (ret < 0)
+               return ret;
+
+       *f = clk_get_rate(priv->clk);
+       return 0;
+}
+
+static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+       clk_disable(priv->clk);
+}
+
 static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
 {
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
 
-       if (p && p->set_pwr)
-               p->set_pwr(pdev, state);
+       p->set_pwr(pdev, state);
 }
 
 static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
 {
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
 
-       if (p && p->get_cd)
-               return p->get_cd(pdev);
-       else
-               return -ENOSYS;
+       return p->get_cd(pdev);
 }
 
 static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
@@ -116,12 +134,14 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        }
 
        mmc_data = &priv->mmc_data;
-       p->pdata = mmc_data;
 
-       if (p->init) {
-               ret = p->init(pdev, &sdhi_ops);
-               if (ret)
-                       goto einit;
+       if (p) {
+               p->pdata = mmc_data;
+               if (p->init) {
+                       ret = p->init(pdev, &sdhi_ops);
+                       if (ret)
+                               goto einit;
+               }
        }
 
        snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
@@ -132,9 +152,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
                goto eclkget;
        }
 
-       mmc_data->hclk = clk_get_rate(priv->clk);
-       mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
-       mmc_data->get_cd = sh_mobile_sdhi_get_cd;
+       mmc_data->clk_enable = sh_mobile_sdhi_clk_enable;
+       mmc_data->clk_disable = sh_mobile_sdhi_clk_disable;
        mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
        if (p) {
                mmc_data->flags = p->tmio_flags;
@@ -142,7 +161,12 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
                        mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
                mmc_data->ocr_mask = p->tmio_ocr_mask;
                mmc_data->capabilities |= p->tmio_caps;
+               mmc_data->capabilities2 |= p->tmio_caps2;
                mmc_data->cd_gpio = p->cd_gpio;
+               if (p->set_pwr)
+                       mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
+               if (p->get_cd)
+                       mmc_data->get_cd = sh_mobile_sdhi_get_cd;
 
                if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
                        priv->param_tx.slave_id = p->dma_slave_tx;
@@ -248,7 +272,7 @@ eirq_card_detect:
 eprobe:
        clk_put(priv->clk);
 eclkget:
-       if (p->cleanup)
+       if (p && p->cleanup)
                p->cleanup(pdev);
 einit:
        kfree(priv);
@@ -263,7 +287,8 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
        int i = 0, irq;
 
-       p->pdata = NULL;
+       if (p)
+               p->pdata = NULL;
 
        tmio_mmc_host_remove(host);
 
@@ -276,7 +301,7 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
 
        clk_put(priv->clk);
 
-       if (p->cleanup)
+       if (p && p->cleanup)
                p->cleanup(pdev);
 
        kfree(priv);
@@ -291,11 +316,18 @@ static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
        .runtime_resume = tmio_mmc_host_runtime_resume,
 };
 
+static const struct of_device_id sh_mobile_sdhi_of_match[] = {
+       { .compatible = "renesas,shmobile-sdhi" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
+
 static struct platform_driver sh_mobile_sdhi_driver = {
        .driver         = {
                .name   = "sh_mobile_sdhi",
                .owner  = THIS_MODULE,
                .pm     = &tmio_mmc_dev_pm_ops,
+               .of_match_table = sh_mobile_sdhi_of_match,
        },
        .probe          = sh_mobile_sdhi_probe,
        .remove         = __devexit_p(sh_mobile_sdhi_remove),
index 9a7996ade58e8aaa597ca81758898669726a305d..0d8a9bbe30bed368226a5020435d00e8218a0b2f 100644 (file)
@@ -34,8 +34,9 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/mfd/tmio.h>
-#include <linux/mmc/cd-gpio.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/mmc/tmio.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
@@ -305,8 +306,8 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
        int c = cmd->opcode;
        u32 irq_mask = TMIO_MASK_CMD;
 
-       /* Command 12 is handled by hardware */
-       if (cmd->opcode == 12 && !cmd->arg) {
+       /* CMD12 is handled by hardware */
+       if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) {
                sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
                return 0;
        }
@@ -449,7 +450,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
        }
 
        if (stop) {
-               if (stop->opcode == 12 && !stop->arg)
+               if (stop->opcode == MMC_STOP_TRANSMISSION && !stop->arg)
                        sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
                else
                        BUG();
@@ -751,6 +752,34 @@ fail:
        mmc_request_done(mmc, mrq);
 }
 
+static int tmio_mmc_clk_update(struct mmc_host *mmc)
+{
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct tmio_mmc_data *pdata = host->pdata;
+       int ret;
+
+       if (!pdata->clk_enable)
+               return -ENOTSUPP;
+
+       ret = pdata->clk_enable(host->pdev, &mmc->f_max);
+       if (!ret)
+               mmc->f_min = mmc->f_max / 512;
+
+       return ret;
+}
+
+static void tmio_mmc_set_power(struct tmio_mmc_host *host, struct mmc_ios *ios)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       if (host->set_pwr)
+               host->set_pwr(host->pdev, ios->power_mode != MMC_POWER_OFF);
+       if (!IS_ERR(mmc->supply.vmmc))
+               /* Errors ignored... */
+               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+                                     ios->power_mode ? ios->vdd : 0);
+}
+
 /* Set MMC clock / power.
  * Note: This controller uses a simple divider scheme therefore it cannot
  * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
@@ -797,32 +826,37 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
         */
        if (ios->power_mode == MMC_POWER_ON && ios->clock) {
                if (!host->power) {
+                       tmio_mmc_clk_update(mmc);
                        pm_runtime_get_sync(dev);
                        host->power = true;
                }
                tmio_mmc_set_clock(host, ios->clock);
                /* power up SD bus */
-               if (host->set_pwr)
-                       host->set_pwr(host->pdev, 1);
+               tmio_mmc_set_power(host, ios);
                /* start bus clock */
                tmio_mmc_clk_start(host);
        } else if (ios->power_mode != MMC_POWER_UP) {
-               if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
-                       host->set_pwr(host->pdev, 0);
+               if (ios->power_mode == MMC_POWER_OFF)
+                       tmio_mmc_set_power(host, ios);
                if (host->power) {
+                       struct tmio_mmc_data *pdata = host->pdata;
+                       tmio_mmc_clk_stop(host);
                        host->power = false;
                        pm_runtime_put(dev);
+                       if (pdata->clk_disable)
+                               pdata->clk_disable(host->pdev);
                }
-               tmio_mmc_clk_stop(host);
        }
 
-       switch (ios->bus_width) {
-       case MMC_BUS_WIDTH_1:
-               sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
-       break;
-       case MMC_BUS_WIDTH_4:
-               sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
-       break;
+       if (host->power) {
+               switch (ios->bus_width) {
+               case MMC_BUS_WIDTH_1:
+                       sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
+               break;
+               case MMC_BUS_WIDTH_4:
+                       sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
+               break;
+               }
        }
 
        /* Let things settle. delay taken from winCE driver */
@@ -841,6 +875,9 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct tmio_mmc_data *pdata = host->pdata;
+       int ret = mmc_gpio_get_ro(mmc);
+       if (ret >= 0)
+               return ret;
 
        return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
                 (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
@@ -850,6 +887,9 @@ static int tmio_mmc_get_cd(struct mmc_host *mmc)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct tmio_mmc_data *pdata = host->pdata;
+       int ret = mmc_gpio_get_cd(mmc);
+       if (ret >= 0)
+               return ret;
 
        if (!pdata->get_cd)
                return -ENOSYS;
@@ -865,6 +905,19 @@ static const struct mmc_host_ops tmio_mmc_ops = {
        .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
 };
 
+static void tmio_mmc_init_ocr(struct tmio_mmc_host *host)
+{
+       struct tmio_mmc_data *pdata = host->pdata;
+       struct mmc_host *mmc = host->mmc;
+
+       mmc_regulator_get_supply(mmc);
+
+       if (!mmc->ocr_avail)
+               mmc->ocr_avail = pdata->ocr_mask ? : MMC_VDD_32_33 | MMC_VDD_33_34;
+       else if (pdata->ocr_mask)
+               dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n");
+}
+
 int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
                                  struct platform_device *pdev,
                                  struct tmio_mmc_data *pdata)
@@ -904,18 +957,14 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
        mmc->ops = &tmio_mmc_ops;
        mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
-       mmc->f_max = pdata->hclk;
-       mmc->f_min = mmc->f_max / 512;
+       mmc->caps2 = pdata->capabilities2;
        mmc->max_segs = 32;
        mmc->max_blk_size = 512;
        mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
                mmc->max_segs;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_seg_size = mmc->max_req_size;
-       if (pdata->ocr_mask)
-               mmc->ocr_avail = pdata->ocr_mask;
-       else
-               mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       tmio_mmc_init_ocr(_host);
 
        _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
                                  mmc->caps & MMC_CAP_NEEDS_POLL ||
@@ -927,6 +976,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (ret < 0)
                goto pm_disable;
 
+       if (tmio_mmc_clk_update(mmc) < 0) {
+               mmc->f_max = pdata->hclk;
+               mmc->f_min = mmc->f_max / 512;
+       }
+
        /*
         * There are 4 different scenarios for the card detection:
         *  1) an external gpio irq handles the cd (best for power savings)
@@ -937,7 +991,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
         *  While we increment the runtime PM counter for all scenarios when
         *  the mmc core activates us by calling an appropriate set_ios(), we
         *  must additionally ensure that in case 2) the tmio mmc hardware stays
-        *  additionally ensure that in case 2) the tmio mmc hardware stays
         *  powered on during runtime for the card detection to work.
         */
        if (_host->native_hotplug)
@@ -948,6 +1001,17 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
        _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK);
        tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
+
+       /* Unmask the IRQs we want to know about */
+       if (!_host->chan_rx)
+               irq_mask |= TMIO_MASK_READOP;
+       if (!_host->chan_tx)
+               irq_mask |= TMIO_MASK_WRITEOP;
+       if (!_host->native_hotplug)
+               irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
+
+       _host->sdcard_irq_mask &= ~irq_mask;
+
        if (pdata->flags & TMIO_MMC_SDIO_IRQ)
                tmio_mmc_enable_sdio_irq(mmc, 0);
 
@@ -961,22 +1025,18 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
-       mmc_add_host(mmc);
+       ret = mmc_add_host(mmc);
+       if (pdata->clk_disable)
+               pdata->clk_disable(pdev);
+       if (ret < 0) {
+               tmio_mmc_host_remove(_host);
+               return ret;
+       }
 
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
 
-       /* Unmask the IRQs we want to know about */
-       if (!_host->chan_rx)
-               irq_mask |= TMIO_MASK_READOP;
-       if (!_host->chan_tx)
-               irq_mask |= TMIO_MASK_WRITEOP;
-       if (!_host->native_hotplug)
-               irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
-
-       tmio_mmc_enable_mmc_irqs(_host, irq_mask);
-
        if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
-               ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio);
+               ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio);
                if (ret < 0) {
                        tmio_mmc_host_remove(_host);
                        return ret;
@@ -1008,7 +1068,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
                 * This means we can miss a card-eject, but this is anyway
                 * possible, because of delayed processing of hotplug events.
                 */
-               mmc_cd_gpio_free(mmc);
+               mmc_gpio_free_cd(mmc);
 
        if (!host->native_hotplug)
                pm_runtime_get_sync(&pdev->dev);
index a90bfe79916d29c6f7c2460e9dc644dadc46904e..334da5f583c021124ea2e64ae7860f513bd9816f 100644 (file)
@@ -63,7 +63,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,
        struct super_block *sb;
        int ret;
 
-       sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, mtd);
+       sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, flags, mtd);
        if (IS_ERR(sb))
                goto out_error;
 
@@ -74,8 +74,6 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,
        pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",
              mtd->index, mtd->name);
 
-       sb->s_flags = flags;
-
        ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
        if (ret < 0) {
                deactivate_locked_super(sb);
index 41371ba1a8117c87aaaf85b63383e60bda6303d6..f3f6cfedd69eb5e1367c196de7e8e249740bb77b 100644 (file)
@@ -102,7 +102,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 static int cafe_device_ready(struct mtd_info *mtd)
 {
        struct cafe_priv *cafe = mtd->priv;
-       int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000);
+       int result = !!(cafe_readl(cafe, NAND_STATUS) & 0x40000000);
        uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
 
        cafe_writel(cafe, irqs, NAND_IRQ);
index a05b7b444d4f1f8a92d6f0e10a2ee1db19d3c722..a6cad5caba788fe8b665270a3fc7494d7a071887 100644 (file)
@@ -920,12 +920,12 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                 */
                memset(chip->oob_poi, ~0, mtd->oobsize);
                chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
-
-               read_page_swap_end(this, buf, mtd->writesize,
-                               this->payload_virt, this->payload_phys,
-                               nfc_geo->payload_size,
-                               payload_virt, payload_phys);
        }
+
+       read_page_swap_end(this, buf, mtd->writesize,
+                       this->payload_virt, this->payload_phys,
+                       nfc_geo->payload_size,
+                       payload_virt, payload_phys);
 exit_nfc:
        return ret;
 }
index c58e6a93f44501d68056d46ea40dc0373d9a51a7..6acc790c2fbb96880ec29642a1d2e7e2528dbee9 100644 (file)
@@ -273,6 +273,26 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
 
 static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
 
+static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
+{
+       int i;
+       u32 *t = trg;
+       const __iomem u32 *s = src;
+
+       for (i = 0; i < (size >> 2); i++)
+               *t++ = __raw_readl(s++);
+}
+
+static void memcpy32_toio(void __iomem *trg, const void *src, int size)
+{
+       int i;
+       u32 __iomem *t = trg;
+       const u32 *s = src;
+
+       for (i = 0; i < (size >> 2); i++)
+               __raw_writel(*s++, t++);
+}
+
 static int check_int_v3(struct mxc_nand_host *host)
 {
        uint32_t tmp;
@@ -519,7 +539,7 @@ static void send_read_id_v3(struct mxc_nand_host *host)
 
        wait_op_done(host, true);
 
-       memcpy_fromio(host->data_buf, host->main_area0, 16);
+       memcpy32_fromio(host->data_buf, host->main_area0, 16);
 }
 
 /* Request the NANDFC to perform a read of the NAND device ID. */
@@ -535,7 +555,7 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host)
        /* Wait for operation to complete */
        wait_op_done(host, true);
 
-       memcpy_fromio(host->data_buf, host->main_area0, 16);
+       memcpy32_fromio(host->data_buf, host->main_area0, 16);
 
        if (this->options & NAND_BUSWIDTH_16) {
                /* compress the ID info */
@@ -797,16 +817,16 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom)
 
        if (bfrom) {
                for (i = 0; i < n - 1; i++)
-                       memcpy_fromio(d + i * j, s + i * t, j);
+                       memcpy32_fromio(d + i * j, s + i * t, j);
 
                /* the last section */
-               memcpy_fromio(d + i * j, s + i * t, mtd->oobsize - i * j);
+               memcpy32_fromio(d + i * j, s + i * t, mtd->oobsize - i * j);
        } else {
                for (i = 0; i < n - 1; i++)
-                       memcpy_toio(&s[i * t], &d[i * j], j);
+                       memcpy32_toio(&s[i * t], &d[i * j], j);
 
                /* the last section */
-               memcpy_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j);
+               memcpy32_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j);
        }
 }
 
@@ -1070,7 +1090,8 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
 
                host->devtype_data->send_page(mtd, NFC_OUTPUT);
 
-               memcpy_fromio(host->data_buf, host->main_area0, mtd->writesize);
+               memcpy32_fromio(host->data_buf, host->main_area0,
+                               mtd->writesize);
                copy_spare(mtd, true);
                break;
 
@@ -1086,7 +1107,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
                break;
 
        case NAND_CMD_PAGEPROG:
-               memcpy_toio(host->main_area0, host->data_buf, mtd->writesize);
+               memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
                copy_spare(mtd, false);
                host->devtype_data->send_page(mtd, NFC_INPUT);
                host->devtype_data->send_cmd(host, command, true);
index d47586cf64ce4af2c802f8783869af8b96ccc0a4..a11253a0fcabd6ef7362b9fcae4972ba06fc4966 100644 (file)
@@ -3501,6 +3501,13 @@ int nand_scan_tail(struct mtd_info *mtd)
        /* propagate ecc info to mtd_info */
        mtd->ecclayout = chip->ecc.layout;
        mtd->ecc_strength = chip->ecc.strength;
+       /*
+        * Initialize bitflip_threshold to its default prior scan_bbt() call.
+        * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
+        * properly set.
+        */
+       if (!mtd->bitflip_threshold)
+               mtd->bitflip_threshold = mtd->ecc_strength;
 
        /* Check, if we should skip the bad block table scan */
        if (chip->options & NAND_SKIP_BBTSCAN)
index 6cc8fbfabb8e2b71d50db215222d380f9e0061a1..cf0cd3146817f9275706f1d4f61b53724d0d5dc1 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -546,12 +546,6 @@ static char *get_partition_name(int i)
        return kstrdup(buf, GFP_KERNEL);
 }
 
-static uint64_t divide(uint64_t n, uint32_t d)
-{
-       do_div(n, d);
-       return n;
-}
-
 /*
  * Initialize the nandsim structure.
  *
@@ -580,7 +574,7 @@ static int init_nandsim(struct mtd_info *mtd)
        ns->geom.oobsz    = mtd->oobsize;
        ns->geom.secsz    = mtd->erasesize;
        ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
-       ns->geom.pgnum    = divide(ns->geom.totsz, ns->geom.pgsz);
+       ns->geom.pgnum    = div_u64(ns->geom.totsz, ns->geom.pgsz);
        ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
        ns->geom.secshift = ffs(ns->geom.secsz) - 1;
        ns->geom.pgshift  = chip->page_shift;
@@ -921,7 +915,7 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 
        if (!rptwear)
                return 0;
-       wear_eb_count = divide(mtd->size, mtd->erasesize);
+       wear_eb_count = div_u64(mtd->size, mtd->erasesize);
        mem = wear_eb_count * sizeof(unsigned long);
        if (mem / sizeof(unsigned long) != wear_eb_count) {
                NS_ERR("Too many erase blocks for wear reporting\n");
index 738ee8dc16cdfb06e2f82d45fecc602d6254ad42..ea4b95b5451c8b6c2ec25a0905c5e4af7e1e76ee 100644 (file)
@@ -29,7 +29,7 @@ config MTD_UBI_WL_THRESHOLD
 
 config MTD_UBI_BEB_RESERVE
        int "Percentage of reserved eraseblocks for bad eraseblocks handling"
-       default 1
+       default 2
        range 0 25
        help
          If the MTD device admits of bad eraseblocks (e.g. NAND flash), UBI
index acec85deb6afe3dd05a5f6d6102c91b4de43d53b..fb55678781813da69b91f81c4aaa5430aef93974 100644 (file)
@@ -1026,7 +1026,7 @@ static long ctrl_cdev_ioctl(struct file *file, unsigned int cmd,
        {
                int ubi_num;
 
-               dbg_gen("dettach MTD device");
+               dbg_gen("detach MTD device");
                err = get_user(ubi_num, (__user int32_t *)argp);
                if (err) {
                        err = -EFAULT;
index f6a7d7ac4b98a6fb1f2dd3b8d2f0abad4b06bd45..8bbfb444b89525cbb9c0a071914a4de0af65f1fe 100644 (file)
@@ -92,7 +92,30 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
 }
 
 /**
- * ubi_calculate_rsvd_pool - calculate how many PEBs must be reserved for bad
+ * ubi_update_reserved - update bad eraseblock handling accounting data.
+ * @ubi: UBI device description object
+ *
+ * This function calculates the gap between current number of PEBs reserved for
+ * bad eraseblock handling and the required level of PEBs that must be
+ * reserved, and if necessary, reserves more PEBs to fill that gap, according
+ * to availability. Should be called with ubi->volumes_lock held.
+ */
+void ubi_update_reserved(struct ubi_device *ubi)
+{
+       int need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
+
+       if (need <= 0 || ubi->avail_pebs == 0)
+               return;
+
+       need = min_t(int, need, ubi->avail_pebs);
+       ubi->avail_pebs -= need;
+       ubi->rsvd_pebs += need;
+       ubi->beb_rsvd_pebs += need;
+       ubi_msg("reserved more %d PEBs for bad PEB handling", need);
+}
+
+/**
+ * ubi_calculate_reserved - calculate how many PEBs must be reserved for bad
  * eraseblock handling.
  * @ubi: UBI device description object
  */
index a1a81c9ea8ce2a8aa7f56accfad3aa7394a51044..84f66e3fa05d7d39ef265a657ec296fd1be1448c 100644 (file)
@@ -647,6 +647,7 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
 int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
                      int length);
 int ubi_check_volume(struct ubi_device *ubi, int vol_id);
+void ubi_update_reserved(struct ubi_device *ubi);
 void ubi_calculate_reserved(struct ubi_device *ubi);
 int ubi_check_pattern(const void *buf, uint8_t patt, int size);
 
index 0669cff8ac3c7d233e40ca6cb1c87878d7fd1457..9169e58c262ec47eaf9b5abb543b12e476af705a 100644 (file)
@@ -443,15 +443,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
        spin_lock(&ubi->volumes_lock);
        ubi->rsvd_pebs -= reserved_pebs;
        ubi->avail_pebs += reserved_pebs;
-       i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
-       if (i > 0) {
-               i = ubi->avail_pebs >= i ? i : ubi->avail_pebs;
-               ubi->avail_pebs -= i;
-               ubi->rsvd_pebs += i;
-               ubi->beb_rsvd_pebs += i;
-               if (i > 0)
-                       ubi_msg("reserve more %d PEBs", i);
-       }
+       ubi_update_reserved(ubi);
        ubi->vol_count -= 1;
        spin_unlock(&ubi->volumes_lock);
 
@@ -558,15 +550,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
                spin_lock(&ubi->volumes_lock);
                ubi->rsvd_pebs += pebs;
                ubi->avail_pebs -= pebs;
-               pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs;
-               if (pebs > 0) {
-                       pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs;
-                       ubi->avail_pebs -= pebs;
-                       ubi->rsvd_pebs += pebs;
-                       ubi->beb_rsvd_pebs += pebs;
-                       if (pebs > 0)
-                               ubi_msg("reserve more %d PEBs", pebs);
-               }
+               ubi_update_reserved(ubi);
                for (i = 0; i < reserved_pebs; i++)
                        new_mapping[i] = vol->eba_tbl[i];
                kfree(vol->eba_tbl);
index 3680aa251dea953d172e224a02b91b713f2dba22..2cf084eb9d524d995c4e3bf72a6d327e5f1ea9cb 100644 (file)
@@ -6,7 +6,7 @@
 #include "bonding.h"
 #include "bond_alb.h"
 
-#ifdef CONFIG_DEBUG_FS
+#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_NET_NS)
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
index b9c2ae62166ddb3e8647a2c756e2ab966d2d8063..2ee76993f052ce517b2f65e92b3dd16b89ebc758 100644 (file)
@@ -3227,6 +3227,12 @@ static int bond_master_netdev_event(unsigned long event,
        switch (event) {
        case NETDEV_CHANGENAME:
                return bond_event_changename(event_bond);
+       case NETDEV_UNREGISTER:
+               bond_remove_proc_entry(event_bond);
+               break;
+       case NETDEV_REGISTER:
+               bond_create_proc_entry(event_bond);
+               break;
        default:
                break;
        }
@@ -4411,8 +4417,6 @@ static void bond_uninit(struct net_device *bond_dev)
 
        bond_work_cancel_all(bond);
 
-       bond_remove_proc_entry(bond);
-
        bond_debug_unregister(bond);
 
        __hw_addr_flush(&bond->mc_list);
@@ -4814,7 +4818,6 @@ static int bond_init(struct net_device *bond_dev)
 
        bond_set_lockdep_class(bond_dev);
 
-       bond_create_proc_entry(bond);
        list_add_tail(&bond->bond_list, &bn->dev_list);
 
        bond_prepare_sysfs_group(bond);
index 9cc15701101b8cfd98ae12799244089daec15c2e..1f78b63d5efe514d82472eaac9d1a3567c3a2981 100644 (file)
@@ -261,7 +261,6 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
        if ((phy_data & BMSR_LSTATUS) == 0) {
                /* link down */
                netif_carrier_off(netdev);
-               netif_stop_queue(netdev);
                hw->hibernate = true;
                if (atl1c_reset_mac(hw) != 0)
                        if (netif_msg_hw(adapter))
index 46b8b7d81633eaa95fb4755a2225494a8b93856a..d09c6b583d17b2570dffdcabc0a4766722af9bf7 100644 (file)
@@ -656,7 +656,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
                        dma_unmap_single(bp->sdev->dma_dev, mapping,
                                             RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
                dev_kfree_skb_any(skb);
-               skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
+               skb = alloc_skb(RX_PKT_BUF_SZ, GFP_ATOMIC | GFP_DMA);
                if (skb == NULL)
                        return -ENOMEM;
                mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
@@ -967,7 +967,7 @@ static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        dma_unmap_single(bp->sdev->dma_dev, mapping, len,
                                             DMA_TO_DEVICE);
 
-               bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA);
+               bounce_skb = alloc_skb(len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb)
                        goto err_out;
 
index ac7b74488531be6f59ee885c23386b01eabd60f5..1fa4927a45b1dadbd6da8fa764792c57c3c67cf0 100644 (file)
@@ -5372,7 +5372,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
                        int k, last;
 
                        if (skb == NULL) {
-                               j++;
+                               j = NEXT_TX_BD(j);
                                continue;
                        }
 
@@ -5384,8 +5384,8 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
                        tx_buf->skb = NULL;
 
                        last = tx_buf->nr_frags;
-                       j++;
-                       for (k = 0; k < last; k++, j++) {
+                       j = NEXT_TX_BD(j);
+                       for (k = 0; k < last; k++, j = NEXT_TX_BD(j)) {
                                tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
                                dma_unmap_page(&bp->pdev->dev,
                                        dma_unmap_addr(tx_buf, mapping),
index c95e7b5e2b85589db86db943c3c77b697394312b..2c89d17cbb292cfc3e971dbf180b95728d8e06b7 100644 (file)
@@ -534,7 +534,8 @@ int cnic_unregister_driver(int ulp_type)
        }
 
        if (atomic_read(&ulp_ops->ref_count) != 0)
-               netdev_warn(dev->netdev, "Failed waiting for ref count to go to zero\n");
+               pr_warn("%s: Failed waiting for ref count to go to zero\n",
+                       __func__);
        return 0;
 
 out_unlock:
@@ -1053,12 +1054,13 @@ static int cnic_init_uio(struct cnic_dev *dev)
 
        uinfo = &udev->cnic_uinfo;
 
-       uinfo->mem[0].addr = dev->netdev->base_addr;
+       uinfo->mem[0].addr = pci_resource_start(dev->pcidev, 0);
        uinfo->mem[0].internal_addr = dev->regview;
-       uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start;
        uinfo->mem[0].memtype = UIO_MEM_PHYS;
 
        if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+               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;
                if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
@@ -1068,6 +1070,8 @@ static int cnic_init_uio(struct cnic_dev *dev)
 
                uinfo->name = "bnx2_cnic";
        } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+               uinfo->mem[0].size = pci_resource_len(dev->pcidev, 0);
+
                uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
                        PAGE_MASK;
                uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
index 0741aded9eb057bbc2454a220bd6a19318e975fa..ab1d80ff0791c36f937b0c06c4a52c33df340591 100644 (file)
@@ -1804,18 +1804,16 @@ void gfar_configure_coalescing(struct gfar_private *priv,
        if (priv->mode == MQ_MG_MODE) {
                baddr = &regs->txic0;
                for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
-                       if (likely(priv->tx_queue[i]->txcoalescing)) {
-                               gfar_write(baddr + i, 0);
+                       gfar_write(baddr + i, 0);
+                       if (likely(priv->tx_queue[i]->txcoalescing))
                                gfar_write(baddr + i, priv->tx_queue[i]->txic);
-                       }
                }
 
                baddr = &regs->rxic0;
                for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
-                       if (likely(priv->rx_queue[i]->rxcoalescing)) {
-                               gfar_write(baddr + i, 0);
+                       gfar_write(baddr + i, 0);
+                       if (likely(priv->rx_queue[i]->rxcoalescing))
                                gfar_write(baddr + i, priv->rx_queue[i]->rxic);
-                       }
                }
        }
 }
@@ -2065,10 +2063,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        return NETDEV_TX_OK;
                }
 
-               /* Steal sock reference for processing TX time stamps */
-               swap(skb_new->sk, skb->sk);
-               swap(skb_new->destructor, skb->destructor);
-               kfree_skb(skb);
+               if (skb->sk)
+                       skb_set_owner_w(skb_new, skb->sk);
+               consume_skb(skb);
                skb = skb_new;
        }
 
index 36db4df09aed6531cf66d893b40449a1b0cceb2c..1f063dcd8f85e39c15da5d82c935113af8044ffb 100644 (file)
@@ -1572,6 +1572,9 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
        ctrl = er32(CTRL);
        status = er32(STATUS);
        rxcw = er32(RXCW);
+       /* SYNCH bit and IV bit are sticky */
+       udelay(10);
+       rxcw = er32(RXCW);
 
        if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
 
index 351a4097b2baec09c53ce45cace4c03c1c8dcb47..76edbc1be33b4d1151e72c24c1f621c830c3a039 100644 (file)
 #define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
 #define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
 #define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
 #define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
 #define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
 
index 238ab2f8a5e7ceff37869043c1ac83d3e41d3b26..e3a7b07df6294781559a72537d7949b711e82d00 100644 (file)
@@ -325,24 +325,46 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
  **/
 static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
 {
-       u16 phy_reg;
-       u32 phy_id;
+       u16 phy_reg = 0;
+       u32 phy_id = 0;
+       s32 ret_val;
+       u16 retry_count;
+
+       for (retry_count = 0; retry_count < 2; retry_count++) {
+               ret_val = e1e_rphy_locked(hw, PHY_ID1, &phy_reg);
+               if (ret_val || (phy_reg == 0xFFFF))
+                       continue;
+               phy_id = (u32)(phy_reg << 16);
 
-       e1e_rphy_locked(hw, PHY_ID1, &phy_reg);
-       phy_id = (u32)(phy_reg << 16);
-       e1e_rphy_locked(hw, PHY_ID2, &phy_reg);
-       phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);
+               ret_val = e1e_rphy_locked(hw, PHY_ID2, &phy_reg);
+               if (ret_val || (phy_reg == 0xFFFF)) {
+                       phy_id = 0;
+                       continue;
+               }
+               phy_id |= (u32)(phy_reg & PHY_REVISION_MASK);
+               break;
+       }
 
        if (hw->phy.id) {
                if (hw->phy.id == phy_id)
                        return true;
-       } else {
-               if ((phy_id != 0) && (phy_id != PHY_REVISION_MASK))
-                       hw->phy.id = phy_id;
+       } else if (phy_id) {
+               hw->phy.id = phy_id;
+               hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK);
                return true;
        }
 
-       return false;
+       /*
+        * In case the PHY needs to be in mdio slow mode,
+        * set slow mode and try to get the PHY id again.
+        */
+       hw->phy.ops.release(hw);
+       ret_val = e1000_set_mdio_slow_mode_hv(hw);
+       if (!ret_val)
+               ret_val = e1000e_get_phy_id(hw);
+       hw->phy.ops.acquire(hw);
+
+       return !ret_val;
 }
 
 /**
index 31d37a2b5ba818e1366945b630f8b187ec9fb15b..623e30b9964de29e091f77564ccd53ce8ba30876 100644 (file)
@@ -496,7 +496,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter,
  * @sk_buff: socket buffer with received data
  **/
 static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
-                             __le16 csum, struct sk_buff *skb)
+                             struct sk_buff *skb)
 {
        u16 status = (u16)status_err;
        u8 errors = (u8)(status_err >> 24);
@@ -511,8 +511,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
        if (status & E1000_RXD_STAT_IXSM)
                return;
 
-       /* TCP/UDP checksum error bit is set */
-       if (errors & E1000_RXD_ERR_TCPE) {
+       /* TCP/UDP checksum error bit or IP checksum error bit is set */
+       if (errors & (E1000_RXD_ERR_TCPE | E1000_RXD_ERR_IPE)) {
                /* let the stack verify checksum errors */
                adapter->hw_csum_err++;
                return;
@@ -523,19 +523,7 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
                return;
 
        /* It must be a TCP or UDP packet with a valid checksum */
-       if (status & E1000_RXD_STAT_TCPCS) {
-               /* TCP checksum is good */
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-       } else {
-               /*
-                * IP fragment with UDP payload
-                * Hardware complements the payload checksum, so we undo it
-                * and then put the value in host order for further stack use.
-                */
-               __sum16 sum = (__force __sum16)swab16((__force u16)csum);
-               skb->csum = csum_unfold(~sum);
-               skb->ip_summed = CHECKSUM_COMPLETE;
-       }
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
        adapter->hw_csum_good++;
 }
 
@@ -954,8 +942,7 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
                skb_put(skb, length);
 
                /* Receive Checksum Offload */
-               e1000_rx_checksum(adapter, staterr,
-                                 rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
+               e1000_rx_checksum(adapter, staterr, skb);
 
                e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
 
@@ -1341,8 +1328,7 @@ copydone:
                total_rx_bytes += skb->len;
                total_rx_packets++;
 
-               e1000_rx_checksum(adapter, staterr,
-                                 rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
+               e1000_rx_checksum(adapter, staterr, skb);
 
                e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
 
@@ -1512,9 +1498,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
                        }
                }
 
-               /* Receive Checksum Offload XXX recompute due to CRC strip? */
-               e1000_rx_checksum(adapter, staterr,
-                                 rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
+               /* Receive Checksum Offload */
+               e1000_rx_checksum(adapter, staterr, skb);
 
                e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
 
@@ -3098,19 +3083,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
 
        /* Enable Receive Checksum Offload for TCP and UDP */
        rxcsum = er32(RXCSUM);
-       if (adapter->netdev->features & NETIF_F_RXCSUM) {
+       if (adapter->netdev->features & NETIF_F_RXCSUM)
                rxcsum |= E1000_RXCSUM_TUOFL;
-
-               /*
-                * IPv4 payload checksum for UDP fragments must be
-                * used in conjunction with packet-split.
-                */
-               if (adapter->rx_ps_pages)
-                       rxcsum |= E1000_RXCSUM_IPPCSE;
-       } else {
+       else
                rxcsum &= ~E1000_RXCSUM_TUOFL;
-               /* no need to clear IPPCSE as it defaults to 0 */
-       }
        ew32(RXCSUM, rxcsum);
 
        if (adapter->hw.mac.type == e1000_pch2lan) {
@@ -5241,22 +5217,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
 
        /* Jumbo frame support */
-       if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
-               if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
-                       e_err("Jumbo Frames not supported.\n");
-                       return -EINVAL;
-               }
-
-               /*
-                * IP payload checksum (enabled with jumbos/packet-split when
-                * Rx checksum is enabled) and generation of RSS hash is
-                * mutually exclusive in the hardware.
-                */
-               if ((netdev->features & NETIF_F_RXCSUM) &&
-                   (netdev->features & NETIF_F_RXHASH)) {
-                       e_err("Jumbo frames cannot be enabled when both receive checksum offload and receive hashing are enabled.  Disable one of the receive offload features before enabling jumbos.\n");
-                       return -EINVAL;
-               }
+       if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) &&
+           !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
+               e_err("Jumbo Frames not supported.\n");
+               return -EINVAL;
        }
 
        /* Supported frame sizes */
@@ -6030,17 +5994,6 @@ static int e1000_set_features(struct net_device *netdev,
                         NETIF_F_RXALL)))
                return 0;
 
-       /*
-        * IP payload checksum (enabled with jumbos/packet-split when Rx
-        * checksum is enabled) and generation of RSS hash is mutually
-        * exclusive in the hardware.
-        */
-       if (adapter->rx_ps_pages &&
-           (features & NETIF_F_RXCSUM) && (features & NETIF_F_RXHASH)) {
-               e_err("Enabling both receive checksum offload and receive hashing is not possible with jumbo frames.  Disable jumbos or enable only one of the receive offload features.\n");
-               return -EINVAL;
-       }
-
        if (changed & NETIF_F_RXFCS) {
                if (features & NETIF_F_RXFCS) {
                        adapter->flags2 &= ~FLAG2_CRC_STRIPPING;
index 8ce67064b9c5802efe098f702486477b424c273e..90eef07943f4d50bbd027646e170abca5abfb1a3 100644 (file)
@@ -357,21 +357,28 @@ static int igbvf_set_coalesce(struct net_device *netdev,
        struct igbvf_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
-       if ((ec->rx_coalesce_usecs > IGBVF_MAX_ITR_USECS) ||
-           ((ec->rx_coalesce_usecs > 3) &&
-            (ec->rx_coalesce_usecs < IGBVF_MIN_ITR_USECS)) ||
-           (ec->rx_coalesce_usecs == 2))
-               return -EINVAL;
-
-       /* convert to rate of irq's per second */
-       if (ec->rx_coalesce_usecs && ec->rx_coalesce_usecs <= 3) {
+       if ((ec->rx_coalesce_usecs >= IGBVF_MIN_ITR_USECS) &&
+            (ec->rx_coalesce_usecs <= IGBVF_MAX_ITR_USECS)) {
+               adapter->current_itr = ec->rx_coalesce_usecs << 2;
+               adapter->requested_itr = 1000000000 /
+                                       (adapter->current_itr * 256);
+       } else if ((ec->rx_coalesce_usecs == 3) ||
+                  (ec->rx_coalesce_usecs == 2)) {
                adapter->current_itr = IGBVF_START_ITR;
                adapter->requested_itr = ec->rx_coalesce_usecs;
-       } else {
-               adapter->current_itr = ec->rx_coalesce_usecs << 2;
+       } else if (ec->rx_coalesce_usecs == 0) {
+               /*
+                * The user's desire is to turn off interrupt throttling
+                * altogether, but due to HW limitations, we can't do that.
+                * Instead we set a very small value in EITR, which would
+                * allow ~967k interrupts per second, but allow the adapter's
+                * internal clocking to still function properly.
+                */
+               adapter->current_itr = 4;
                adapter->requested_itr = 1000000000 /
                                        (adapter->current_itr * 256);
-       }
+       } else
+               return -EINVAL;
 
        writel(adapter->current_itr,
               hw->hw_addr + adapter->rx_ring->itr_register);
index 18ca3bcadf0cc10d152528654b41edcaab13f1df..e242104ab471a23ed6203dc4a4e4cda82edf44e7 100644 (file)
@@ -6647,6 +6647,11 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
                return -EINVAL;
        }
 
+       if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+               e_err(drv, "Enable failed, SR-IOV enabled\n");
+               return -EINVAL;
+       }
+
        /* Hardware supports up to 8 traffic classes */
        if (tc > adapter->dcb_cfg.num_tcs.pg_tcs ||
            (hw->mac.type == ixgbe_mac_82598EB &&
index f69ec4288b104e6c175b54b17fe4ceecc363fba1..41e32257a4e873e37d4daf24798400c394416b69 100644 (file)
@@ -201,6 +201,9 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_adapter *adapter,
        unsigned int i, eop, count = 0;
        unsigned int total_bytes = 0, total_packets = 0;
 
+       if (test_bit(__IXGBEVF_DOWN, &adapter->state))
+               return true;
+
        i = tx_ring->next_to_clean;
        eop = tx_ring->tx_buffer_info[i].next_to_watch;
        eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
@@ -969,8 +972,6 @@ static irqreturn_t ixgbevf_msix_clean_tx(int irq, void *data)
        r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
        for (i = 0; i < q_vector->txr_count; i++) {
                tx_ring = &(adapter->tx_ring[r_idx]);
-               tx_ring->total_bytes = 0;
-               tx_ring->total_packets = 0;
                ixgbevf_clean_tx_irq(adapter, tx_ring);
                r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
                                      r_idx + 1);
@@ -994,16 +995,6 @@ static irqreturn_t ixgbevf_msix_clean_rx(int irq, void *data)
        struct ixgbe_hw *hw = &adapter->hw;
        struct ixgbevf_ring  *rx_ring;
        int r_idx;
-       int i;
-
-       r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
-       for (i = 0; i < q_vector->rxr_count; i++) {
-               rx_ring = &(adapter->rx_ring[r_idx]);
-               rx_ring->total_bytes = 0;
-               rx_ring->total_packets = 0;
-               r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
-                                     r_idx + 1);
-       }
 
        if (!q_vector->rxr_count)
                return IRQ_HANDLED;
index fb8377da1687c2166d3ebda44f5a7fa24c6bd785..4b785e10f2ed7d0994d17df944f01907480a767e 100644 (file)
@@ -51,7 +51,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
                                                csum);
-
+               wmb();
                entry = (++priv->cur_tx) % txsize;
                desc = priv->dma_tx + entry;
 
@@ -59,6 +59,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                                            len, DMA_TO_DEVICE);
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
+               wmb();
                priv->hw->desc->set_tx_owner(desc);
                priv->tx_skbuff[entry] = NULL;
        } else {
index 51b3b68528ee8a429385f5083355125f2b4260c4..ea3003edde18671ac13fd887fda9abc5d8a018ce 100644 (file)
@@ -1212,6 +1212,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
                wmb();
                priv->hw->desc->set_tx_owner(desc);
+               wmb();
        }
 
        /* Interrupt on completition only for the latest segment */
@@ -1227,6 +1228,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* To avoid raise condition */
        priv->hw->desc->set_tx_owner(first);
+       wmb();
 
        priv->cur_tx++;
 
@@ -1290,6 +1292,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
                }
                wmb();
                priv->hw->desc->set_rx_owner(p + entry);
+               wmb();
        }
 }
 
index d614c374ed9d2ada5b6923e288528b8201a09807..3b5c4571b55e3c922a4b6e5a94a0a4a8adcb2fce 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/dma-mapping.h>
index 39ea0674dcde8cde6b31d71202b9b81873897ba6..5c120189ec86d419866b7320c36f4d618dc5df64 100644 (file)
@@ -46,7 +46,13 @@ static int mdio_mux_read(struct mii_bus *bus, int phy_id, int regnum)
        struct mdio_mux_parent_bus *pb = cb->parent;
        int r;
 
-       mutex_lock(&pb->mii_bus->mdio_lock);
+       /* In theory multiple mdio_mux could be stacked, thus creating
+        * more than a single level of nesting.  But in practice,
+        * SINGLE_DEPTH_NESTING will cover the vast majority of use
+        * cases.  We use it, instead of trying to handle the general
+        * case.
+        */
+       mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING);
        r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
        if (r)
                goto out;
@@ -71,7 +77,7 @@ static int mdio_mux_write(struct mii_bus *bus, int phy_id,
 
        int r;
 
-       mutex_lock(&pb->mii_bus->mdio_lock);
+       mutex_lock_nested(&pb->mii_bus->mdio_lock, SINGLE_DEPTH_NESTING);
        r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
        if (r)
                goto out;
index 3767a122586043512cd6ded88b562fd9b97df88f..a051cedd64bde58179a1cb539b94a888fcd29416 100644 (file)
@@ -197,6 +197,10 @@ err:
 static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
 {
        struct usbnet *dev = usb_get_intfdata(intf);
+
+       /* can be called while disconnecting */
+       if (!dev)
+               return 0;
        return qmi_wwan_manage_power(dev, on);
 }
 
@@ -342,6 +346,15 @@ static const struct driver_info    qmi_wwan_force_int1 = {
        .data           = BIT(1), /* interface whitelist bitmap */
 };
 
+static const struct driver_info qmi_wwan_force_int2 = {
+       .description    = "Qualcomm WWAN/QMI device",
+       .flags          = FLAG_WWAN,
+       .bind           = qmi_wwan_bind_shared,
+       .unbind         = qmi_wwan_unbind_shared,
+       .manage_power   = qmi_wwan_manage_power,
+       .data           = BIT(2), /* interface whitelist bitmap */
+};
+
 static const struct driver_info        qmi_wwan_force_int3 = {
        .description    = "Qualcomm WWAN/QMI device",
        .flags          = FLAG_WWAN,
@@ -494,6 +507,15 @@ static const struct usb_device_id products[] = {
                .bInterfaceProtocol = 0xff,
                .driver_info        = (unsigned long)&qmi_wwan_force_int4,
        },
+       {       /* ZTE MF60 */
+               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
+               .idVendor           = 0x19d2,
+               .idProduct          = 0x1402,
+               .bInterfaceClass    = 0xff,
+               .bInterfaceSubClass = 0xff,
+               .bInterfaceProtocol = 0xff,
+               .driver_info        = (unsigned long)&qmi_wwan_force_int2,
+       },
        {       /* Sierra Wireless MC77xx in QMI mode */
                .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
                .idVendor           = 0x1199,
index c54b7d37bff159f1fc8a7482a4d8bdfe806b9beb..420d69b2674ceae1282fcc9d8cbbc38d8c5d00af 100644 (file)
@@ -143,6 +143,7 @@ struct ath_common {
        u32 keymax;
        DECLARE_BITMAP(keymap, ATH_KEYMAX);
        DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX);
+       DECLARE_BITMAP(ccmp_keymap, ATH_KEYMAX);
        enum ath_crypt_caps crypt_caps;
 
        unsigned int clockrate;
index 1c68e564f503197c9642ba1cae5e9633325fbe8c..995ca8e1302efc7562ff9905d8e91d00ffb25f74 100644 (file)
@@ -622,7 +622,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 
        if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
                if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
-                   ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
+                   ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) &&
                     !ah->is_pciexpress)) {
                        ah->config.serialize_regmode =
                                SER_REG_MODE_ON;
index e1fcc68124dc3bc78359cf72e2da459ddf9c4560..0735aeb3b26cefcd15c2847a1775718d36cecbc6 100644 (file)
@@ -695,9 +695,9 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
                        __skb_unlink(skb, &rx_edma->rx_fifo);
                        list_add_tail(&bf->list, &sc->rx.rxbuf);
                        ath_rx_edma_buf_link(sc, qtype);
-               } else {
-                       bf = NULL;
                }
+
+               bf = NULL;
        }
 
        *dest = bf;
@@ -822,7 +822,8 @@ static bool ath9k_rx_accept(struct ath_common *common,
         * descriptor does contain a valid key index. This has been observed
         * mostly with CCMP encryption.
         */
-       if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID)
+       if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID ||
+           !test_bit(rx_stats->rs_keyix, common->ccmp_keymap))
                rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS;
 
        if (!rx_stats->rs_datalen) {
index 0e81904956cf1c04fa37ad01e65282b55e2bf8f9..5c54aa43ca2d81b3936d917aeb68f7331aabb34b 100644 (file)
@@ -556,6 +556,9 @@ int ath_key_config(struct ath_common *common,
                return -EIO;
 
        set_bit(idx, common->keymap);
+       if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
+               set_bit(idx, common->ccmp_keymap);
+
        if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
                set_bit(idx + 64, common->keymap);
                set_bit(idx, common->tkip_keymap);
@@ -582,6 +585,7 @@ void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
                return;
 
        clear_bit(key->hw_key_idx, common->keymap);
+       clear_bit(key->hw_key_idx, common->ccmp_keymap);
        if (key->cipher != WLAN_CIPHER_SUITE_TKIP)
                return;
 
index f1f8bd09bd87fd378cb405d6aa56a38eafe4fb3c..c8baf020c20f7a4fd73104bd56a87cae375b935e 100644 (file)
@@ -1072,7 +1072,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
        meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
        /* create a bounce buffer in zone_dma on mapping failure. */
        if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
-               bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+               bounce_skb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
                if (!bounce_skb) {
                        ring->current_slot = old_top_slot;
                        ring->used_slots = old_used_slots;
index 509301a5e7e264ae079201a246ded0252582308a..ff5d689e13f34884222b58fe06291140db1f9682 100644 (file)
@@ -3405,7 +3405,7 @@ il4965_remove_dynamic_key(struct il_priv *il,
                return 0;
        }
 
-       if (il->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) {
+       if (il->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_INVALID) {
                IL_WARN("Removing wrong key %d 0x%x\n", keyconf->keyidx,
                        key_flags);
                spin_unlock_irqrestore(&il->sta_lock, flags);
@@ -3420,7 +3420,7 @@ il4965_remove_dynamic_key(struct il_priv *il,
        memset(&il->stations[sta_id].sta.key, 0, sizeof(struct il4965_keyinfo));
        il->stations[sta_id].sta.key.key_flags =
            STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
-       il->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
+       il->stations[sta_id].sta.key.key_offset = keyconf->hw_key_idx;
        il->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
        il->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
index cbf2dc18341f58eec6141158e0c6d3aaad02d12b..5d4807c2b56d80aaafe47089a2498b29856ba40c 100644 (file)
@@ -4767,14 +4767,12 @@ il_bg_watchdog(unsigned long data)
                return;
 
        /* monitor and check for other stuck queues */
-       if (il_is_any_associated(il)) {
-               for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
-                       /* skip as we already checked the command queue */
-                       if (cnt == il->cmd_queue)
-                               continue;
-                       if (il_check_stuck_queue(il, cnt))
-                               return;
-               }
+       for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) {
+               /* skip as we already checked the command queue */
+               if (cnt == il->cmd_queue)
+                       continue;
+               if (il_check_stuck_queue(il, cnt))
+                       return;
        }
 
        mod_timer(&il->watchdog,
index 3ee23134c02b9b96ee184a5999e9577bf6452511..013680332f075be85a9035bcec33eaec0c2e9285 100644 (file)
@@ -796,6 +796,18 @@ int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
        switch (op) {
        case ADD:
                ret = iwlagn_mac_sta_add(hw, vif, sta);
+               if (ret)
+                       break;
+               /*
+                * Clear the in-progress flag, the AP station entry was added
+                * but we'll initialize LQ only when we've associated (which
+                * would also clear the in-progress flag). This is necessary
+                * in case we never initialize LQ because association fails.
+                */
+               spin_lock_bh(&priv->sta_lock);
+               priv->stations[iwl_sta_id(sta)].used &=
+                       ~IWL_STA_UCODE_INPROGRESS;
+               spin_unlock_bh(&priv->sta_lock);
                break;
        case REMOVE:
                ret = iwlagn_mac_sta_remove(hw, vif, sta);
index 9c44088054dd90bd967626d8416e63c083225fc8..900ee129e825987dfb2dbe6b485bfa0bb40dbc74 100644 (file)
@@ -256,7 +256,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
        else
                last_seq = priv->rx_seq[tid];
 
-       if (last_seq >= new_node->start_win)
+       if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
+           last_seq >= new_node->start_win)
                new_node->start_win = last_seq + 1;
 
        new_node->win_size = win_size;
@@ -596,5 +597,5 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
        spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
 
        INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
-       memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
+       mwifiex_reset_11n_rx_seq_num(priv);
 }
index f1bffebabc60a6ab1059276664bc3f3f71e129bb..6c9815a0f5d8b0d7aebcb5d6a9953a24819ad45a 100644 (file)
 
 #define ADDBA_RSP_STATUS_ACCEPT 0
 
+#define MWIFIEX_DEF_11N_RX_SEQ_NUM     0xffff
+
+static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
+{
+       memset(priv->rx_seq, 0xff, sizeof(priv->rx_seq));
+}
+
 int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *,
                               u16 seqNum,
                               u16 tid, u8 *ta,
index ce61b6fae1c99f44ead5f0c226b26b882cdacf43..5c7fd185373cfb37c0ee57e62b9b54135af505b7 100644 (file)
@@ -958,6 +958,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
        case NL80211_HIDDEN_SSID_ZERO_CONTENTS:
                /* firmware doesn't support this type of hidden SSID */
        default:
+               kfree(bss_cfg);
                return -EINVAL;
        }
 
index ceb82cd749cc7ba1ca2054ae0b675802d2194190..383820a52beba0d62428614131adbe42def1e5db 100644 (file)
@@ -213,6 +213,7 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
                /* save assoc resp ie index after auto-indexing */
                *assoc_idx = *((u16 *)pos);
 
+       kfree(ap_custom_ie);
        return ret;
 }
 
index e0377473282f05fab01835578cb9b2579a40217f..fc8a9bfa1248305fababa37b59ca90110a57afaa 100644 (file)
@@ -978,10 +978,10 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
                dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
                adapter->event_cause = *(u32 *) skb->data;
 
-               skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN);
-
                if ((skb->len > 0) && (skb->len  < MAX_EVENT_SIZE))
-                       memcpy(adapter->event_body, skb->data, skb->len);
+                       memcpy(adapter->event_body,
+                              skb->data + MWIFIEX_EVENT_HEADER_LEN,
+                              skb->len);
 
                /* event cause has been saved to adapter->event_cause */
                adapter->event_received = true;
index 4ace5a3dcd237c5aada48223e224a7f943ef2692..11e731f3581c2dbf4856d8676ca6ee66c12ccabe 100644 (file)
@@ -406,9 +406,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                break;
 
        case EVENT_UAP_STA_ASSOC:
-               skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
                memset(&sinfo, 0, sizeof(sinfo));
-               event = (struct mwifiex_assoc_event *)adapter->event_skb->data;
+               event = (struct mwifiex_assoc_event *)
+                       (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
                if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
                        len = -1;
 
@@ -433,9 +433,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                                 GFP_KERNEL);
                break;
        case EVENT_UAP_STA_DEAUTH:
-               skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
-               cfg80211_del_sta(priv->netdev, adapter->event_skb->data,
-                                GFP_KERNEL);
+               cfg80211_del_sta(priv->netdev, adapter->event_body +
+                                MWIFIEX_UAP_EVENT_EXTRA_HEADER, GFP_KERNEL);
                break;
        case EVENT_UAP_BSS_IDLE:
                priv->media_connected = false;
index 49ebf20c56ebc0ac98dc8d5b25bc3a1164847020..22a5916564b84099576e1c554b37d1fcbcd420b2 100644 (file)
@@ -49,6 +49,7 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
        struct device *dev = adapter->dev;
        u32 recv_type;
        __le32 tmp;
+       int ret;
 
        if (adapter->hs_activated)
                mwifiex_process_hs_config(adapter);
@@ -69,16 +70,19 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                case MWIFIEX_USB_TYPE_CMD:
                        if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) {
                                dev_err(dev, "CMD: skb->len too large\n");
-                               return -1;
+                               ret = -1;
+                               goto exit_restore_skb;
                        } else if (!adapter->curr_cmd) {
                                dev_dbg(dev, "CMD: no curr_cmd\n");
                                if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
                                        mwifiex_process_sleep_confirm_resp(
                                                        adapter, skb->data,
                                                        skb->len);
-                                       return 0;
+                                       ret = 0;
+                                       goto exit_restore_skb;
                                }
-                               return -1;
+                               ret = -1;
+                               goto exit_restore_skb;
                        }
 
                        adapter->curr_cmd->resp_skb = skb;
@@ -87,20 +91,22 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
                case MWIFIEX_USB_TYPE_EVENT:
                        if (skb->len < sizeof(u32)) {
                                dev_err(dev, "EVENT: skb->len too small\n");
-                               return -1;
+                               ret = -1;
+                               goto exit_restore_skb;
                        }
                        skb_copy_from_linear_data(skb, &tmp, sizeof(u32));
                        adapter->event_cause = le32_to_cpu(tmp);
-                       skb_pull(skb, sizeof(u32));
                        dev_dbg(dev, "event_cause %#x\n", adapter->event_cause);
 
                        if (skb->len > MAX_EVENT_SIZE) {
                                dev_err(dev, "EVENT: event body too large\n");
-                               return -1;
+                               ret = -1;
+                               goto exit_restore_skb;
                        }
 
-                       skb_copy_from_linear_data(skb, adapter->event_body,
-                                                 skb->len);
+                       memcpy(adapter->event_body, skb->data +
+                              MWIFIEX_EVENT_HEADER_LEN, skb->len);
+
                        adapter->event_received = true;
                        adapter->event_skb = skb;
                        break;
@@ -124,6 +130,12 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter,
        }
 
        return -EINPROGRESS;
+
+exit_restore_skb:
+       /* The buffer will be reused for further cmds/events */
+       skb_push(skb, INTF_HEADER_LEN);
+
+       return ret;
 }
 
 static void mwifiex_usb_rx_complete(struct urb *urb)
index f3fc6551585780b08724bb8112457caafeef220e..3fa4d417699381225e853a56238e0d8506a2f99b 100644 (file)
@@ -404,6 +404,8 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
                priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
                priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
 
+               mwifiex_reset_11n_rx_seq_num(priv);
+
                atomic_set(&priv->wmm.tx_pkts_queued, 0);
                atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
        }
@@ -1221,6 +1223,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
 
        if (!ptr->is_11n_enabled ||
            mwifiex_is_ba_stream_setup(priv, ptr, tid) ||
+           priv->wps.session_enable ||
            ((priv->sec_info.wpa_enabled ||
              priv->sec_info.wpa2_enabled) &&
             !priv->wpa_is_gtk_set)) {
index d357d1ed92f6ddc363f0babca95652d8f446b3c2..74ecc33fdd90c249d5fcd3c46d68d646113e0985 100644 (file)
@@ -436,8 +436,8 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
        case QID_RX:
                if (!rt2x00queue_full(queue))
                        rt2x00queue_for_each_entry(queue,
-                                                  Q_INDEX_DONE,
                                                   Q_INDEX,
+                                                  Q_INDEX_DONE,
                                                   NULL,
                                                   rt2x00usb_kick_rx_entry);
                break;
index d228358e6a403b9c8eee56d63ce4991058975dc9..9970c2b1b19979dc3577472c7c21e27703a38a76 100644 (file)
@@ -301,9 +301,11 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
        {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
        {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
+       {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
        {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
        {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
        {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
+       {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/
        /* HP - Lite-On ,8188CUS Slim Combo */
        {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)},
        {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */
@@ -346,6 +348,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
        {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/
        {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
+       {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/
        {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/
        {RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/
        {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/
index 54156b0b5c2d7defe6b42791d022d4c982fd945f..d7b907e67170348e70302e6a1cfe70642a8c6f7e 100644 (file)
@@ -1,7 +1,6 @@
 config WLCORE
        tristate "TI wlcore support"
        depends on WL_TI && GENERIC_HARDIRQS && MAC80211
-       depends on INET
        select FW_LOADER
        ---help---
          This module contains the main code for TI WLAN chips.  It abstracts
index 343ad29e211c66768491e325046ff0b58bcb15ec..e44f8c2d239d253afc045164834f0476b94cf932 100644 (file)
@@ -317,10 +317,9 @@ static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *l
        for(; lookup->compatible != NULL; lookup++) {
                if (!of_device_is_compatible(np, lookup->compatible))
                        continue;
-               if (of_address_to_resource(np, 0, &res))
-                       continue;
-               if (res.start != lookup->phys_addr)
-                       continue;
+               if (!of_address_to_resource(np, 0, &res))
+                       if (res.start != lookup->phys_addr)
+                               continue;
                pr_debug("%s: devname=%s\n", np->full_name, lookup->name);
                return lookup;
        }
@@ -462,4 +461,5 @@ int of_platform_populate(struct device_node *root,
        of_node_put(root);
        return rc;
 }
+EXPORT_SYMBOL_GPL(of_platform_populate);
 #endif /* CONFIG_OF_ADDRESS */
index efc4b7f308cfd6e1c37a44a0407c6e070f9d514e..f3cfa0b9adfa30fb9a95593d4f422ef25c2f4836 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2010 ARM Ltd.
+ * Copyright 2012 Advanced Micro Devices, Inc., Robert Richter
  *
  * Perf-events backend for OProfile.
  */
@@ -25,7 +26,7 @@ static int oprofile_perf_enabled;
 static DEFINE_MUTEX(oprofile_perf_mutex);
 
 static struct op_counter_config *counter_config;
-static struct perf_event **perf_events[NR_CPUS];
+static DEFINE_PER_CPU(struct perf_event **, perf_events);
 static int num_counters;
 
 /*
@@ -38,7 +39,7 @@ static void op_overflow_handler(struct perf_event *event,
        u32 cpu = smp_processor_id();
 
        for (id = 0; id < num_counters; ++id)
-               if (perf_events[cpu][id] == event)
+               if (per_cpu(perf_events, cpu)[id] == event)
                        break;
 
        if (id != num_counters)
@@ -74,7 +75,7 @@ static int op_create_counter(int cpu, int event)
 {
        struct perf_event *pevent;
 
-       if (!counter_config[event].enabled || perf_events[cpu][event])
+       if (!counter_config[event].enabled || per_cpu(perf_events, cpu)[event])
                return 0;
 
        pevent = perf_event_create_kernel_counter(&counter_config[event].attr,
@@ -91,18 +92,18 @@ static int op_create_counter(int cpu, int event)
                return -EBUSY;
        }
 
-       perf_events[cpu][event] = pevent;
+       per_cpu(perf_events, cpu)[event] = pevent;
 
        return 0;
 }
 
 static void op_destroy_counter(int cpu, int event)
 {
-       struct perf_event *pevent = perf_events[cpu][event];
+       struct perf_event *pevent = per_cpu(perf_events, cpu)[event];
 
        if (pevent) {
                perf_event_release_kernel(pevent);
-               perf_events[cpu][event] = NULL;
+               per_cpu(perf_events, cpu)[event] = NULL;
        }
 }
 
@@ -257,12 +258,12 @@ void oprofile_perf_exit(void)
 
        for_each_possible_cpu(cpu) {
                for (id = 0; id < num_counters; ++id) {
-                       event = perf_events[cpu][id];
+                       event = per_cpu(perf_events, cpu)[id];
                        if (event)
                                perf_event_release_kernel(event);
                }
 
-               kfree(perf_events[cpu]);
+               kfree(per_cpu(perf_events, cpu));
        }
 
        kfree(counter_config);
@@ -277,8 +278,6 @@ int __init oprofile_perf_init(struct oprofile_operations *ops)
        if (ret)
                return ret;
 
-       memset(&perf_events, 0, sizeof(perf_events));
-
        num_counters = perf_num_counters();
        if (num_counters <= 0) {
                pr_info("oprofile: no performance counters\n");
@@ -298,9 +297,9 @@ int __init oprofile_perf_init(struct oprofile_operations *ops)
        }
 
        for_each_possible_cpu(cpu) {
-               perf_events[cpu] = kcalloc(num_counters,
+               per_cpu(perf_events, cpu) = kcalloc(num_counters,
                                sizeof(struct perf_event *), GFP_KERNEL);
-               if (!perf_events[cpu]) {
+               if (!per_cpu(perf_events, cpu)) {
                        pr_info("oprofile: failed to allocate %d perf events "
                                        "for cpu %d\n", num_counters, cpu);
                        ret = -ENOMEM;
index bf0cee629b60f8bb763b4407f631e7ba7e778aa8..099f46cd8e87a4ca823dc24f707458857f26eaa5 100644 (file)
@@ -748,6 +748,18 @@ static int pci_pm_suspend_noirq(struct device *dev)
 
        pci_pm_set_unknown_state(pci_dev);
 
+       /*
+        * Some BIOSes from ASUS have a bug: If a USB EHCI host controller's
+        * PCI COMMAND register isn't 0, the BIOS assumes that the controller
+        * hasn't been quiesced and tries to turn it off.  If the controller
+        * is already in D3, this can hang or cause memory corruption.
+        *
+        * Since the value of the COMMAND register doesn't matter once the
+        * device has been suspended, we can safely set it to 0 here.
+        */
+       if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
+               pci_write_config_word(pci_dev, PCI_COMMAND, 0);
+
        return 0;
 }
 
index 77cb54a65cde10885d7b0b4406ae103faca9e8a2..447e83472c01558705d0685f7fd6af17a6f8deef 100644 (file)
@@ -1744,11 +1744,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
        if (target_state == PCI_POWER_ERROR)
                return -EIO;
 
-       /* Some devices mustn't be in D3 during system sleep */
-       if (target_state == PCI_D3hot &&
-                       (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP))
-               return 0;
-
        pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
 
        error = pci_set_power_state(dev, target_state);
index 194b243a281782864c0e6284fdcc23546e9f15b1..2a75216775410df88e19fd9faa21e0045c16d15d 100644 (file)
@@ -2929,32 +2929,6 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
 
-/*
- * The Intel 6 Series/C200 Series chipset's EHCI controllers on many
- * ASUS motherboards will cause memory corruption or a system crash
- * if they are in D3 while the system is put into S3 sleep.
- */
-static void __devinit asus_ehci_no_d3(struct pci_dev *dev)
-{
-       const char *sys_info;
-       static const char good_Asus_board[] = "P8Z68-V";
-
-       if (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP)
-               return;
-       if (dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK)
-               return;
-       sys_info = dmi_get_system_info(DMI_BOARD_NAME);
-       if (sys_info && memcmp(sys_info, good_Asus_board,
-                       sizeof(good_Asus_board) - 1) == 0)
-               return;
-
-       dev_info(&dev->dev, "broken D3 during system sleep on ASUS\n");
-       dev->dev_flags |= PCI_DEV_FLAGS_NO_D3_DURING_SLEEP;
-       device_set_wakeup_capable(&dev->dev, false);
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
-
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
                          struct pci_fixup *end)
 {
index dd6d93aa5334b6bcd8b39ef3e4227047148a49cc..90c837f469a612be02304415a85c384d7b9363af 100644 (file)
@@ -474,7 +474,9 @@ static int __devinit imx_pinctrl_parse_groups(struct device_node *np,
                grp->configs[j] = config & ~IMX_PAD_SION;
        }
 
+#ifdef DEBUG
        IMX_PMX_DUMP(info, grp->pins, grp->mux_mode, grp->configs, grp->npins);
+#endif
 
        return 0;
 }
index 7737d4d71a3cc7fa8541a603615a29b96b9f173f..e9bf71fbedcafc9a14f14d662d6ec6ca1d7436bc 100644 (file)
@@ -1950,6 +1950,8 @@ static struct imx_pin_reg imx6q_pin_regs[] = {
        IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 5, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__GPIO_1_12 */
        IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 6, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__SJC_DONE */
        IMX_PIN_REG(MX6Q_PAD_SD2_DAT3, 0x0744, 0x035C, 7, 0x0000, 0), /* MX6Q_PAD_SD2_DAT3__ANATOP_TESTO_3 */
+       IMX_PIN_REG(MX6Q_PAD_ENET_RX_ER, 0x04EC, 0x01D8, 0, 0x0000, 0), /* MX6Q_PAD_ENET_RX_ER__ANATOP_USBOTG_ID */
+       IMX_PIN_REG(MX6Q_PAD_GPIO_1, 0x05F4, 0x0224, 3, 0x0000, 0), /* MX6Q_PAD_GPIO_1__ANATOP_USBOTG_ID */
 };
 
 /* Pad names for the pinmux subsystem */
index 3e7e47d6b38526178b0985bf0e7162f8fab16d70..dd9e6f26416da777dfb66231aca0c9f86bade9a0 100644 (file)
@@ -1198,7 +1198,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
                if (!pdata)
                        return -ENOMEM;
 
-               if (of_get_property(np, "supports-sleepmode", NULL))
+               if (of_get_property(np, "st,supports-sleepmode", NULL))
                        pdata->supports_sleepmode = true;
 
                if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
index ce875dc365e5f2ed0fa61dda0162fd1bb5be3cd1..c8f40c9c0428310c8dcf7db2110c73a119dc3150 100644 (file)
@@ -1877,8 +1877,7 @@ static int acer_platform_remove(struct platform_device *device)
        return 0;
 }
 
-static int acer_platform_suspend(struct platform_device *dev,
-pm_message_t state)
+static int acer_suspend(struct device *dev)
 {
        u32 value;
        struct acer_data *data = &interface->data;
@@ -1900,7 +1899,7 @@ pm_message_t state)
        return 0;
 }
 
-static int acer_platform_resume(struct platform_device *device)
+static int acer_resume(struct device *dev)
 {
        struct acer_data *data = &interface->data;
 
@@ -1916,6 +1915,8 @@ static int acer_platform_resume(struct platform_device *device)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
+
 static void acer_platform_shutdown(struct platform_device *device)
 {
        struct acer_data *data = &interface->data;
@@ -1931,11 +1932,10 @@ static struct platform_driver acer_platform_driver = {
        .driver = {
                .name = "acer-wmi",
                .owner = THIS_MODULE,
+               .pm = &acer_pm,
        },
        .probe = acer_platform_probe,
        .remove = acer_platform_remove,
-       .suspend = acer_platform_suspend,
-       .resume = acer_platform_resume,
        .shutdown = acer_platform_shutdown,
 };
 
index 94f93b621d7b67474808fb6c33cdf81248ca3936..e2230a2b2f8e3e82056ef7d197eb877999f337e9 100644 (file)
@@ -362,15 +362,18 @@ static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
        return cmpc_remove_acpi_notify_device(acpi);
 }
 
-static int cmpc_tablet_resume(struct acpi_device *acpi)
+static int cmpc_tablet_resume(struct device *dev)
 {
-       struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
+       struct input_dev *inputdev = dev_get_drvdata(dev);
+
        unsigned long long val = 0;
-       if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
+       if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val)))
                input_report_switch(inputdev, SW_TABLET_MODE, !val);
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
+
 static const struct acpi_device_id cmpc_tablet_device_ids[] = {
        {CMPC_TABLET_HID, 0},
        {"", 0}
@@ -384,9 +387,9 @@ static struct acpi_driver cmpc_tablet_acpi_driver = {
        .ops = {
                .add = cmpc_tablet_add,
                .remove = cmpc_tablet_remove,
-               .resume = cmpc_tablet_resume,
                .notify = cmpc_tablet_handler,
-       }
+       },
+       .drv.pm = &cmpc_tablet_pm,
 };
 
 
index da267eae8ba85bc151fef55a0255a9d850429141..d2e41735a47b2d6178ef290211e0d13373ece570 100644 (file)
@@ -440,12 +440,14 @@ static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
        return 0;
 }
 
-static int acpi_fujitsu_resume(struct acpi_device *adev)
+static int acpi_fujitsu_resume(struct device *dev)
 {
        fujitsu_reset();
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
+
 static struct acpi_driver acpi_fujitsu_driver = {
        .name  = MODULENAME,
        .class = "hotkey",
@@ -453,8 +455,8 @@ static struct acpi_driver acpi_fujitsu_driver = {
        .ops   = {
                .add    = acpi_fujitsu_add,
                .remove = acpi_fujitsu_remove,
-               .resume = acpi_fujitsu_resume,
-       }
+       },
+       .drv.pm = &acpi_fujitsu_pm,
 };
 
 static int __init fujitsu_module_init(void)
index 24a3ae065f1b9ffce58f6c6aaa595f2384c11bac..d9ab6f64dcec0185148075dca8f4ef8fda1319bf 100644 (file)
@@ -305,17 +305,19 @@ static int hdaps_probe(struct platform_device *dev)
        return 0;
 }
 
-static int hdaps_resume(struct platform_device *dev)
+static int hdaps_resume(struct device *dev)
 {
        return hdaps_device_init();
 }
 
+static SIMPLE_DEV_PM_OPS(hdaps_pm, NULL, hdaps_resume);
+
 static struct platform_driver hdaps_driver = {
        .probe = hdaps_probe,
-       .resume = hdaps_resume,
        .driver = {
                .name = "hdaps",
                .owner = THIS_MODULE,
+               .pm = &hdaps_pm,
        },
 };
 
index 22b2dfa731480769ffbf18f6e447ee8ac54c5741..f4d91154ad67cca5d260cc681c5f7464dea0e87c 100644 (file)
@@ -353,20 +353,22 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 
 
 #ifdef CONFIG_PM
-static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
+static int lis3lv02d_suspend(struct device *dev)
 {
        /* make sure the device is off when we suspend */
        lis3lv02d_poweroff(&lis3_dev);
        return 0;
 }
 
-static int lis3lv02d_resume(struct acpi_device *device)
+static int lis3lv02d_resume(struct device *dev)
 {
        return lis3lv02d_poweron(&lis3_dev);
 }
+
+static SIMPLE_DEV_PM_OPS(hp_accel_pm, lis3lv02d_suspend, lis3lv02d_resume);
+#define HP_ACCEL_PM (&hp_accel_pm)
 #else
-#define lis3lv02d_suspend NULL
-#define lis3lv02d_resume NULL
+#define HP_ACCEL_PM NULL
 #endif
 
 /* For the HP MDPS aka 3D Driveguard */
@@ -377,9 +379,8 @@ static struct acpi_driver lis3lv02d_driver = {
        .ops = {
                .add     = lis3lv02d_add,
                .remove  = lis3lv02d_remove,
-               .suspend = lis3lv02d_suspend,
-               .resume  = lis3lv02d_resume,
-       }
+       },
+       .drv.pm = HP_ACCEL_PM,
 };
 
 static int __init lis3lv02d_init_module(void)
index 4f20f8dd3d7cd054d2b3ef4c72cda6c75e265094..17f6dfd8dbfb093a332d7d9d9ebd572df9b850e7 100644 (file)
@@ -694,10 +694,10 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
 static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
 {
        int ret, i;
-       unsigned long cfg;
+       int cfg;
        struct ideapad_private *priv;
 
-       if (read_method_int(adevice->handle, "_CFG", (int *)&cfg))
+       if (read_method_int(adevice->handle, "_CFG", &cfg))
                return -ENODEV;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -721,7 +721,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
                goto input_failed;
 
        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
-               if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg))
+               if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
                        ideapad_register_rfkill(adevice, i);
                else
                        priv->rfk[i] = NULL;
index 0ffdb3cde2bbc3ff569fee774dcd842333585031..5051aa970e0af3144c294516a92282ead76bb06b 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/string.h>
 #include <linux/tick.h>
 #include <linux/timer.h>
+#include <linux/dmi.h>
 #include <drm/i915_drm.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
@@ -1485,6 +1486,24 @@ static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = {
 
 MODULE_DEVICE_TABLE(pci, ips_id_table);
 
+static int ips_blacklist_callback(const struct dmi_system_id *id)
+{
+       pr_info("Blacklisted intel_ips for %s\n", id->ident);
+       return 1;
+}
+
+static const struct dmi_system_id ips_blacklist[] = {
+       {
+               .callback = ips_blacklist_callback,
+               .ident = "HP ProBook",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook"),
+               },
+       },
+       { }     /* terminating entry */
+};
+
 static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        u64 platform_info;
@@ -1494,6 +1513,9 @@ static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id)
        u16 htshi, trc, trc_required_mask;
        u8 tse;
 
+       if (dmi_check_system(ips_blacklist))
+               return -ENODEV;
+
        ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL);
        if (!ips)
                return -ENOMEM;
@@ -1697,21 +1719,6 @@ static void ips_remove(struct pci_dev *dev)
        dev_dbg(&dev->dev, "IPS driver removed\n");
 }
 
-#ifdef CONFIG_PM
-static int ips_suspend(struct pci_dev *dev, pm_message_t state)
-{
-       return 0;
-}
-
-static int ips_resume(struct pci_dev *dev)
-{
-       return 0;
-}
-#else
-#define ips_suspend NULL
-#define ips_resume NULL
-#endif /* CONFIG_PM */
-
 static void ips_shutdown(struct pci_dev *dev)
 {
 }
@@ -1721,8 +1728,6 @@ static struct pci_driver ips_pci_driver = {
        .id_table = ips_id_table,
        .probe = ips_probe,
        .remove = ips_remove,
-       .suspend = ips_suspend,
-       .resume = ips_resume,
        .shutdown = ips_shutdown,
 };
 
index 5ae9cd9c7e6e10f4da2dc254725f397286598731..ea7422f6fa0343328c2074e4df63d60488d55f9b 100644 (file)
@@ -418,23 +418,23 @@ static struct thermal_device_info *initialize_sensor(int index)
 
 /**
  * mid_thermal_resume - resume routine
- * @pdev: platform device structure
+ * @dev: device structure
  *
  * mid thermal resume: re-initializes the adc. Can sleep.
  */
-static int mid_thermal_resume(struct platform_device *pdev)
+static int mid_thermal_resume(struct device *dev)
 {
-       return mid_initialize_adc(&pdev->dev);
+       return mid_initialize_adc(dev);
 }
 
 /**
  * mid_thermal_suspend - suspend routine
- * @pdev: platform device structure
+ * @dev: device structure
  *
  * mid thermal suspend implements the suspend functionality
  * by stopping the ADC. Can sleep.
  */
-static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int mid_thermal_suspend(struct device *dev)
 {
        /*
         * This just stops the ADC and does not disable it.
@@ -444,6 +444,9 @@ static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
        return configure_adc(0);
 }
 
+static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
+                        mid_thermal_suspend, mid_thermal_resume);
+
 /**
  * read_curr_temp - reads the current temperature and stores in temp
  * @temp: holds the current temperature value after reading
@@ -557,10 +560,9 @@ static struct platform_driver mid_thermal_driver = {
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
+               .pm = &mid_thermal_pm,
        },
        .probe = mid_thermal_probe,
-       .suspend = mid_thermal_suspend,
-       .resume = mid_thermal_resume,
        .remove = __devexit_p(mid_thermal_remove),
        .id_table = therm_id_table,
 };
index bb5132128b339235f599969d75a692bd4099dfce..f64441844317f513c6ec8db521fb0bad37afbda8 100644 (file)
@@ -85,7 +85,8 @@
 #define MSI_STANDARD_EC_TOUCHPAD_ADDRESS       0xe4
 #define MSI_STANDARD_EC_TOUCHPAD_MASK          (1 << 4)
 
-static int msi_laptop_resume(struct platform_device *device);
+static int msi_laptop_resume(struct device *device);
+static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume);
 
 #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
 
@@ -437,8 +438,8 @@ static struct platform_driver msipf_driver = {
        .driver = {
                .name = "msi-laptop-pf",
                .owner = THIS_MODULE,
+               .pm = &msi_laptop_pm,
        },
-       .resume = msi_laptop_resume,
 };
 
 static struct platform_device *msipf_device;
@@ -752,7 +753,7 @@ err_bluetooth:
        return retval;
 }
 
-static int msi_laptop_resume(struct platform_device *device)
+static int msi_laptop_resume(struct device *device)
 {
        u8 data;
        int result;
index ffff8b4b4949502dbc56997f873594da7314b4b4..24480074bcf047c40b219dcf5b055ce829d865d7 100644 (file)
@@ -177,7 +177,6 @@ enum SINF_BITS { SINF_NUM_BATTERIES = 0,
 
 static int acpi_pcc_hotkey_add(struct acpi_device *device);
 static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
-static int acpi_pcc_hotkey_resume(struct acpi_device *device);
 static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
 
 static const struct acpi_device_id pcc_device_ids[] = {
@@ -189,6 +188,9 @@ static const struct acpi_device_id pcc_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
 
+static int acpi_pcc_hotkey_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
+
 static struct acpi_driver acpi_pcc_driver = {
        .name =         ACPI_PCC_DRIVER_NAME,
        .class =        ACPI_PCC_CLASS,
@@ -196,9 +198,9 @@ static struct acpi_driver acpi_pcc_driver = {
        .ops =          {
                                .add =          acpi_pcc_hotkey_add,
                                .remove =       acpi_pcc_hotkey_remove,
-                               .resume =       acpi_pcc_hotkey_resume,
                                .notify =       acpi_pcc_hotkey_notify,
                        },
+       .drv.pm =       &acpi_pcc_hotkey_pm,
 };
 
 static const struct key_entry panasonic_keymap[] = {
@@ -538,11 +540,15 @@ static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
 
 /* kernel module interface */
 
-static int acpi_pcc_hotkey_resume(struct acpi_device *device)
+static int acpi_pcc_hotkey_resume(struct device *dev)
 {
-       struct pcc_acpi *pcc = acpi_driver_data(device);
+       struct pcc_acpi *pcc;
+
+       if (!dev)
+               return -EINVAL;
 
-       if (device == NULL || pcc == NULL)
+       pcc = acpi_driver_data(to_acpi_device(dev));
+       if (!pcc)
                return -EINVAL;
 
        ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
index 210d4ae547c201eafd438ca896357f10f22a3502..9363969ad07adf65cefe1a6aa918ca47363ca907 100644 (file)
@@ -973,7 +973,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
                               struct device_attribute *attr,
                               const char *buffer, size_t count)
 {
-       unsigned long value = 0;
+       int value;
        int ret = 0;
        struct sony_nc_value *item =
            container_of(attr, struct sony_nc_value, devattr);
@@ -984,7 +984,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
        if (count > 31)
                return -EINVAL;
 
-       if (kstrtoul(buffer, 10, &value))
+       if (kstrtoint(buffer, 10, &value))
                return -EINVAL;
 
        if (item->validate)
@@ -994,7 +994,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
                return value;
 
        ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
-                       (int *)&value, NULL);
+                              &value, NULL);
        if (ret < 0)
                return -EIO;
 
@@ -1010,6 +1010,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 struct sony_backlight_props {
        struct backlight_device *dev;
        int                     handle;
+       int                     cmd_base;
        u8                      offset;
        u8                      maxlvl;
 };
@@ -1037,7 +1038,7 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd)
        struct sony_backlight_props *sdev =
                (struct sony_backlight_props *)bl_get_data(bd);
 
-       sony_call_snc_handle(sdev->handle, 0x0200, &result);
+       sony_call_snc_handle(sdev->handle, sdev->cmd_base + 0x100, &result);
 
        return (result & 0xff) - sdev->offset;
 }
@@ -1049,7 +1050,8 @@ static int sony_nc_update_status_ng(struct backlight_device *bd)
                (struct sony_backlight_props *)bl_get_data(bd);
 
        value = bd->props.brightness + sdev->offset;
-       if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result))
+       if (sony_call_snc_handle(sdev->handle, sdev->cmd_base | (value << 0x10),
+                               &result))
                return -EIO;
 
        return value;
@@ -1172,6 +1174,11 @@ static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
 /*
  * ACPI callbacks
  */
+enum event_types {
+       HOTKEY = 1,
+       KILLSWITCH,
+       GFX_SWITCH
+};
 static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
        u32 real_ev = event;
@@ -1196,7 +1203,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
                /* hotkey event */
                case 0x0100:
                case 0x0127:
-                       ev_type = 1;
+                       ev_type = HOTKEY;
                        real_ev = sony_nc_hotkeys_decode(event, handle);
 
                        if (real_ev > 0)
@@ -1216,7 +1223,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
                         * update the rfkill device status when the
                         * switch is moved.
                         */
-                       ev_type = 2;
+                       ev_type = KILLSWITCH;
                        sony_call_snc_handle(handle, 0x0100, &result);
                        real_ev = result & 0x03;
 
@@ -1226,6 +1233,24 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
                        break;
 
+               case 0x0128:
+               case 0x0146:
+                       /* Hybrid GFX switching */
+                       sony_call_snc_handle(handle, 0x0000, &result);
+                       dprintk("GFX switch event received (reason: %s)\n",
+                                       (result & 0x01) ?
+                                       "switch change" : "unknown");
+
+                       /* verify the switch state
+                        * 1: discrete GFX
+                        * 0: integrated GFX
+                        */
+                       sony_call_snc_handle(handle, 0x0100, &result);
+
+                       ev_type = GFX_SWITCH;
+                       real_ev = result & 0xff;
+                       break;
+
                default:
                        dprintk("Unknown event 0x%x for handle 0x%x\n",
                                        event, handle);
@@ -1238,7 +1263,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
        } else {
                /* old style event */
-               ev_type = 1;
+               ev_type = HOTKEY;
                sony_laptop_report_input_event(real_ev);
        }
 
@@ -1452,7 +1477,7 @@ static void sony_nc_function_resume(void)
                                &result);
 }
 
-static int sony_nc_resume(struct acpi_device *device)
+static int sony_nc_resume(struct device *dev)
 {
        struct sony_nc_value *item;
        acpi_handle handle;
@@ -1484,6 +1509,8 @@ static int sony_nc_resume(struct acpi_device *device)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
+
 static void sony_nc_rfkill_cleanup(void)
 {
        int i;
@@ -1893,32 +1920,33 @@ static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
         *  bits 4,5: store the limit into the EC
         *  bits 6,7: store the limit into the battery
         */
+       cmd = 0;
 
-       /*
-        * handle 0x0115 should allow storing on battery too;
-        * handle 0x0136 same as 0x0115 + health status;
-        * handle 0x013f, same as 0x0136 but no storing on the battery
-        *
-        * Store only inside the EC for now, regardless the handle number
-        */
-       if (value == 0)
-               /* disable limits */
-               cmd = 0x0;
+       if (value > 0) {
+               if (value <= 50)
+                       cmd = 0x20;
 
-       else if (value <= 50)
-               cmd = 0x21;
+               else if (value <= 80)
+                       cmd = 0x10;
 
-       else if (value <= 80)
-               cmd = 0x11;
+               else if (value <= 100)
+                       cmd = 0x30;
 
-       else if (value <= 100)
-               cmd = 0x31;
+               else
+                       return -EINVAL;
 
-       else
-               return -EINVAL;
+               /*
+                * handle 0x0115 should allow storing on battery too;
+                * handle 0x0136 same as 0x0115 + health status;
+                * handle 0x013f, same as 0x0136 but no storing on the battery
+                */
+               if (bcare_ctl->handle != 0x013f)
+                       cmd = cmd | (cmd << 2);
 
-       if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100,
-                               &result))
+               cmd = (cmd | 0x1) << 0x10;
+       }
+
+       if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result))
                return -EIO;
 
        return count;
@@ -2113,7 +2141,7 @@ static ssize_t sony_nc_thermal_mode_show(struct device *dev,
                struct device_attribute *attr, char *buffer)
 {
        ssize_t count = 0;
-       unsigned int mode = sony_nc_thermal_mode_get();
+       int mode = sony_nc_thermal_mode_get();
 
        if (mode < 0)
                return mode;
@@ -2472,6 +2500,7 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 {
        u64 offset;
        int i;
+       int lvl_table_len = 0;
        u8 min = 0xff, max = 0x00;
        unsigned char buffer[32] = { 0 };
 
@@ -2480,8 +2509,6 @@ static void sony_nc_backlight_ng_read_limits(int handle,
        props->maxlvl = 0xff;
 
        offset = sony_find_snc_handle(handle);
-       if (offset < 0)
-               return;
 
        /* try to read the boundaries from ACPI tables, if we fail the above
         * defaults should be reasonable
@@ -2491,11 +2518,21 @@ static void sony_nc_backlight_ng_read_limits(int handle,
        if (i < 0)
                return;
 
+       switch (handle) {
+       case 0x012f:
+       case 0x0137:
+               lvl_table_len = 9;
+               break;
+       case 0x143:
+               lvl_table_len = 16;
+               break;
+       }
+
        /* the buffer lists brightness levels available, brightness levels are
         * from position 0 to 8 in the array, other values are used by ALS
         * control.
         */
-       for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) {
+       for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) {
 
                dprintk("Brightness level: %d\n", buffer[i]);
 
@@ -2520,16 +2557,24 @@ static void sony_nc_backlight_setup(void)
        const struct backlight_ops *ops = NULL;
        struct backlight_properties props;
 
-       if (sony_find_snc_handle(0x12f) != -1) {
+       if (sony_find_snc_handle(0x12f) >= 0) {
                ops = &sony_backlight_ng_ops;
+               sony_bl_props.cmd_base = 0x0100;
                sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
-       } else if (sony_find_snc_handle(0x137) != -1) {
+       } else if (sony_find_snc_handle(0x137) >= 0) {
                ops = &sony_backlight_ng_ops;
+               sony_bl_props.cmd_base = 0x0100;
                sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
+       } else if (sony_find_snc_handle(0x143) >= 0) {
+               ops = &sony_backlight_ng_ops;
+               sony_bl_props.cmd_base = 0x3000;
+               sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
+               max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
+
        } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
                                                &unused))) {
                ops = &sony_backlight_ops;
@@ -2597,6 +2642,12 @@ static int sony_nc_add(struct acpi_device *device)
                }
        }
 
+       result = sony_laptop_setup_input(device);
+       if (result) {
+               pr_err("Unable to create input devices\n");
+               goto outplatform;
+       }
+
        if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
                                         &handle))) {
                int arg = 1;
@@ -2614,12 +2665,6 @@ static int sony_nc_add(struct acpi_device *device)
        }
 
        /* setup input devices and helper fifo */
-       result = sony_laptop_setup_input(device);
-       if (result) {
-               pr_err("Unable to create input devices\n");
-               goto outsnc;
-       }
-
        if (acpi_video_backlight_support()) {
                pr_info("brightness ignored, must be controlled by ACPI video driver\n");
        } else {
@@ -2667,22 +2712,21 @@ static int sony_nc_add(struct acpi_device *device)
 
        return 0;
 
-      out_sysfs:
+out_sysfs:
        for (item = sony_nc_values; item->name; ++item) {
                device_remove_file(&sony_pf_device->dev, &item->devattr);
        }
        sony_nc_backlight_cleanup();
-
-       sony_laptop_remove_input();
-
-      outsnc:
        sony_nc_function_cleanup(sony_pf_device);
        sony_nc_handles_cleanup(sony_pf_device);
 
-      outpresent:
+outplatform:
+       sony_laptop_remove_input();
+
+outpresent:
        sony_pf_remove();
 
-      outwalk:
+outwalk:
        sony_nc_rfkill_cleanup();
        return result;
 }
@@ -2728,9 +2772,9 @@ static struct acpi_driver sony_nc_driver = {
        .ops = {
                .add = sony_nc_add,
                .remove = sony_nc_remove,
-               .resume = sony_nc_resume,
                .notify = sony_nc_notify,
                },
+       .drv.pm = &sony_nc_pm,
 };
 
 /*********** SPIC (SNY6001) Device ***********/
@@ -4243,19 +4287,22 @@ err_free_resources:
        return result;
 }
 
-static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
+static int sony_pic_suspend(struct device *dev)
 {
-       if (sony_pic_disable(device))
+       if (sony_pic_disable(to_acpi_device(dev)))
                return -ENXIO;
        return 0;
 }
 
-static int sony_pic_resume(struct acpi_device *device)
+static int sony_pic_resume(struct device *dev)
 {
-       sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+       sony_pic_enable(to_acpi_device(dev),
+                       spic_dev.cur_ioport, spic_dev.cur_irq);
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
+
 static const struct acpi_device_id sony_pic_device_ids[] = {
        {SONY_PIC_HID, 0},
        {"", 0},
@@ -4269,9 +4316,8 @@ static struct acpi_driver sony_pic_driver = {
        .ops = {
                .add = sony_pic_add,
                .remove = sony_pic_remove,
-               .suspend = sony_pic_suspend,
-               .resume = sony_pic_resume,
                },
+       .drv.pm = &sony_pic_pm,
 };
 
 static struct dmi_system_id __initdata sonypi_dmi_table[] = {
index 8b5610d884186b63b693b6b7aee2ceb705fc47ee..d5fd4a1193f84e9fd3db93835962a86bd8aefbac 100644 (file)
@@ -277,7 +277,7 @@ struct ibm_struct {
        int (*write) (char *);
        void (*exit) (void);
        void (*resume) (void);
-       void (*suspend) (pm_message_t state);
+       void (*suspend) (void);
        void (*shutdown) (void);
 
        struct list_head all_drivers;
@@ -922,8 +922,7 @@ static struct input_dev *tpacpi_inputdev;
 static struct mutex tpacpi_inputdev_send_mutex;
 static LIST_HEAD(tpacpi_all_drivers);
 
-static int tpacpi_suspend_handler(struct platform_device *pdev,
-                                 pm_message_t state)
+static int tpacpi_suspend_handler(struct device *dev)
 {
        struct ibm_struct *ibm, *itmp;
 
@@ -931,13 +930,13 @@ static int tpacpi_suspend_handler(struct platform_device *pdev,
                                 &tpacpi_all_drivers,
                                 all_drivers) {
                if (ibm->suspend)
-                       (ibm->suspend)(state);
+                       (ibm->suspend)();
        }
 
        return 0;
 }
 
-static int tpacpi_resume_handler(struct platform_device *pdev)
+static int tpacpi_resume_handler(struct device *dev)
 {
        struct ibm_struct *ibm, *itmp;
 
@@ -951,6 +950,9 @@ static int tpacpi_resume_handler(struct platform_device *pdev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(tpacpi_pm,
+                        tpacpi_suspend_handler, tpacpi_resume_handler);
+
 static void tpacpi_shutdown_handler(struct platform_device *pdev)
 {
        struct ibm_struct *ibm, *itmp;
@@ -967,9 +969,8 @@ static struct platform_driver tpacpi_pdriver = {
        .driver = {
                .name = TPACPI_DRVR_NAME,
                .owner = THIS_MODULE,
+               .pm = &tpacpi_pm,
        },
-       .suspend = tpacpi_suspend_handler,
-       .resume = tpacpi_resume_handler,
        .shutdown = tpacpi_shutdown_handler,
 };
 
@@ -3758,7 +3759,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
        }
 }
 
-static void hotkey_suspend(pm_message_t state)
+static void hotkey_suspend(void)
 {
        /* Do these on suspend, we get the events on early resume! */
        hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
@@ -6329,7 +6330,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
        return 0;
 }
 
-static void brightness_suspend(pm_message_t state)
+static void brightness_suspend(void)
 {
        tpacpi_brightness_checkpoint_nvram();
 }
@@ -6748,7 +6749,7 @@ static struct snd_kcontrol_new volume_alsa_control_mute __devinitdata = {
        .get = volume_alsa_mute_get,
 };
 
-static void volume_suspend(pm_message_t state)
+static void volume_suspend(void)
 {
        tpacpi_volume_checkpoint_nvram();
 }
@@ -8107,7 +8108,7 @@ static void fan_exit(void)
        flush_workqueue(tpacpi_wq);
 }
 
-static void fan_suspend(pm_message_t state)
+static void fan_suspend(void)
 {
        int rc;
 
index dab10f6edcd43186e2af9a397d909a0ce607694f..c13ba5bac93f1c594f22ecb1b6e701586793a081 100644 (file)
@@ -1296,10 +1296,9 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
        }
 }
 
-static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
-                               pm_message_t state)
+static int toshiba_acpi_suspend(struct device *device)
 {
-       struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+       struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
        u32 result;
 
        if (dev->hotkey_dev)
@@ -1308,9 +1307,9 @@ static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
        return 0;
 }
 
-static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
+static int toshiba_acpi_resume(struct device *device)
 {
-       struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+       struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
        u32 result;
 
        if (dev->hotkey_dev)
@@ -1319,6 +1318,9 @@ static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
+                        toshiba_acpi_suspend, toshiba_acpi_resume);
+
 static struct acpi_driver toshiba_acpi_driver = {
        .name   = "Toshiba ACPI driver",
        .owner  = THIS_MODULE,
@@ -1328,9 +1330,8 @@ static struct acpi_driver toshiba_acpi_driver = {
                .add            = toshiba_acpi_add,
                .remove         = toshiba_acpi_remove,
                .notify         = toshiba_acpi_notify,
-               .suspend        = toshiba_acpi_suspend,
-               .resume         = toshiba_acpi_resume,
        },
+       .drv.pm = &toshiba_acpi_pm,
 };
 
 static int __init toshiba_acpi_init(void)
index 5fb7186694df034f85d47fd6c3d5e8a03ac5a51b..715a43cb5e3c49020c24a07c302ec3792fcce84a 100644 (file)
@@ -34,7 +34,6 @@ MODULE_LICENSE("GPL");
 static int toshiba_bt_rfkill_add(struct acpi_device *device);
 static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type);
 static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
-static int toshiba_bt_resume(struct acpi_device *device);
 
 static const struct acpi_device_id bt_device_ids[] = {
        { "TOS6205", 0},
@@ -42,6 +41,9 @@ static const struct acpi_device_id bt_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, bt_device_ids);
 
+static int toshiba_bt_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
+
 static struct acpi_driver toshiba_bt_rfkill_driver = {
        .name =         "Toshiba BT",
        .class =        "Toshiba",
@@ -50,9 +52,9 @@ static struct acpi_driver toshiba_bt_rfkill_driver = {
                                .add =          toshiba_bt_rfkill_add,
                                .remove =       toshiba_bt_rfkill_remove,
                                .notify =       toshiba_bt_rfkill_notify,
-                               .resume =       toshiba_bt_resume,
                        },
        .owner =        THIS_MODULE,
+       .drv.pm =       &toshiba_bt_pm,
 };
 
 
@@ -88,9 +90,9 @@ static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
        toshiba_bluetooth_enable(device->handle);
 }
 
-static int toshiba_bt_resume(struct acpi_device *device)
+static int toshiba_bt_resume(struct device *dev)
 {
-       return toshiba_bluetooth_enable(device->handle);
+       return toshiba_bluetooth_enable(to_acpi_device(dev)->handle);
 }
 
 static int toshiba_bt_rfkill_add(struct acpi_device *device)
index fad153dc0355e33db828fe6d3e12ef97bea2b429..849c07c13bf6cae790c3e99dfb402f55b88a2a1f 100644 (file)
@@ -77,11 +77,13 @@ static void ebook_switch_notify(struct acpi_device *device, u32 event)
        }
 }
 
-static int ebook_switch_resume(struct acpi_device *device)
+static int ebook_switch_resume(struct device *dev)
 {
-       return ebook_send_state(device);
+       return ebook_send_state(to_acpi_device(dev));
 }
 
+static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
+
 static int ebook_switch_add(struct acpi_device *device)
 {
        struct ebook_switch *button;
@@ -161,10 +163,10 @@ static struct acpi_driver xo15_ebook_driver = {
        .ids = ebook_device_ids,
        .ops = {
                .add = ebook_switch_add,
-               .resume = ebook_switch_resume,
                .remove = ebook_switch_remove,
                .notify = ebook_switch_notify,
        },
+       .drv.pm = &ebook_switch_pm,
 };
 
 static int __init xo15_ebook_init(void)
index c86b8864e411feceb66924be2b8cc4170c0db74c..f34c3be6c9fed92bdaf227016f4540b8edda0f89 100644 (file)
@@ -20,6 +20,7 @@ menuconfig REGULATOR
 
          If unsure, say no.
 
+
 if REGULATOR
 
 config REGULATOR_DEBUG
@@ -88,6 +89,13 @@ config REGULATOR_AAT2870
          If you have a AnalogicTech AAT2870 say Y to enable the
          regulator driver.
 
+config REGULATOR_ARIZONA
+       tristate "Wolfson Arizona class devices"
+       depends on MFD_ARIZONA
+       help
+         Support for the regulators found on Wolfson Arizona class
+         devices.
+
 config REGULATOR_DA903X
        tristate "Dialog Semiconductor DA9030/DA9034 regulators"
        depends on PMIC_DA903X
@@ -195,6 +203,14 @@ config REGULATOR_MAX8998
          via I2C bus. The provided regulator is suitable for S3C6410
          and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
 
+config REGULATOR_MAX77686
+       tristate "Maxim 77686 regulator"
+       depends on MFD_MAX77686
+       help
+         This driver controls a Maxim 77686 regulator
+         via I2C bus. The provided regulator is suitable for
+         Exynos-4 chips to control VARM and VINT voltages.
+
 config REGULATOR_PCAP
        tristate "Motorola PCAP2 regulator driver"
        depends on EZX_PCAP
@@ -216,6 +232,19 @@ config REGULATOR_LP3972
         Say Y here to support the voltage regulators and convertors
         on National Semiconductors LP3972 PMIC
 
+config REGULATOR_LP872X
+       bool "TI/National Semiconductor LP8720/LP8725 voltage regulators"
+       depends on I2C=y
+       select REGMAP_I2C
+       help
+         This driver supports LP8720/LP8725 PMIC
+
+config REGULATOR_LP8788
+       bool "TI LP8788 Power Regulators"
+       depends on MFD_LP8788
+       help
+         This driver supports LP8788 voltage regulator chip.
+
 config REGULATOR_PCF50633
        tristate "NXP PCF50633 regulator driver"
         depends on MFD_PCF50633
@@ -233,6 +262,14 @@ config REGULATOR_RC5T583
          through regulator interface. The device supports multiple DCDC/LDO
          outputs which can be controlled by i2c communication.
 
+config REGULATOR_S2MPS11
+       tristate "Samsung S2MPS11 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.
+
 config REGULATOR_S5M8767
        tristate "Samsung S5M8767A voltage regulator"
        depends on MFD_S5M_CORE
index 977fd46909abdb9b9bd2c62f9d26737465613c7a..3342615cf25e165b50ff8a1ab56f3a556207f41b 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
 obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
+obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
@@ -23,6 +24,9 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
+obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
+obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
+obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_MAX8649)        += max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
@@ -30,6 +34,7 @@ obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
 obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
 obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
+obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
@@ -37,6 +42,7 @@ obj-$(CONFIG_REGULATOR_PALMAS) += palmas-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_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
index 06776ca945f2a57b12501c11fa70febd3c55a389..6f45bfd22e832f71f04c337c686bc762672d7842 100644 (file)
@@ -33,11 +33,6 @@ struct aat2870_regulator {
        struct aat2870_data *aat2870;
        struct regulator_desc desc;
 
-       const int *voltages; /* uV */
-
-       int min_uV;
-       int max_uV;
-
        u8 enable_addr;
        u8 enable_shift;
        u8 enable_mask;
@@ -47,14 +42,6 @@ struct aat2870_regulator {
        u8 voltage_mask;
 };
 
-static int aat2870_ldo_list_voltage(struct regulator_dev *rdev,
-                                   unsigned selector)
-{
-       struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
-
-       return ri->voltages[selector];
-}
-
 static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
                                       unsigned selector)
 {
@@ -111,7 +98,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
 }
 
 static struct regulator_ops aat2870_ldo_ops = {
-       .list_voltage = aat2870_ldo_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .set_voltage_sel = aat2870_ldo_set_voltage_sel,
        .get_voltage_sel = aat2870_ldo_get_voltage_sel,
        .enable = aat2870_ldo_enable,
@@ -119,7 +106,7 @@ static struct regulator_ops aat2870_ldo_ops = {
        .is_enabled = aat2870_ldo_is_enabled,
 };
 
-static const int aat2870_ldo_voltages[] = {
+static const unsigned int aat2870_ldo_voltages[] = {
        1200000, 1300000, 1500000, 1600000,
        1800000, 2000000, 2200000, 2500000,
        2600000, 2700000, 2800000, 2900000,
@@ -132,13 +119,11 @@ static const int aat2870_ldo_voltages[] = {
                        .name = #ids,                   \
                        .id = AAT2870_ID_##ids,         \
                        .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \
+                       .volt_table = aat2870_ldo_voltages, \
                        .ops = &aat2870_ldo_ops,        \
                        .type = REGULATOR_VOLTAGE,      \
                        .owner = THIS_MODULE,           \
                },                                      \
-               .voltages = aat2870_ldo_voltages,       \
-               .min_uV = 1200000,                      \
-               .max_uV = 3300000,                      \
        }
 
 static struct aat2870_regulator aat2870_regulators[] = {
index 03f4d9c604ec19717abfb2d57f64b8c49c6e42af..182b553059c9c82a15f8ff164d64c5d37e708c52 100644 (file)
  * @dev: handle to the device
  * @plfdata: AB3100 platform data passed in at probe time
  * @regreg: regulator register number in the AB3100
- * @fixed_voltage: a fixed voltage for this regulator, if this
- *          0 the voltages array is used instead.
- * @typ_voltages: an array of available typical voltages for
- *          this regulator
- * @voltages_len: length of the array of available voltages
  */
 struct ab3100_regulator {
        struct regulator_dev *rdev;
        struct device *dev;
        struct ab3100_platform_data *plfdata;
        u8 regreg;
-       int fixed_voltage;
-       int const *typ_voltages;
-       u8 voltages_len;
 };
 
 /* The order in which registers are initialized */
@@ -80,7 +72,7 @@ static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = {
 #define LDO_C_VOLTAGE 2650000
 #define LDO_D_VOLTAGE 2650000
 
-static const int ldo_e_buck_typ_voltages[] = {
+static const unsigned int ldo_e_buck_typ_voltages[] = {
        1800000,
        1400000,
        1300000,
@@ -90,7 +82,7 @@ static const int ldo_e_buck_typ_voltages[] = {
        900000,
 };
 
-static const int ldo_f_typ_voltages[] = {
+static const unsigned int ldo_f_typ_voltages[] = {
        1800000,
        1400000,
        1300000,
@@ -101,21 +93,21 @@ static const int ldo_f_typ_voltages[] = {
        2650000,
 };
 
-static const int ldo_g_typ_voltages[] = {
+static const unsigned int ldo_g_typ_voltages[] = {
        2850000,
        2750000,
        1800000,
        1500000,
 };
 
-static const int ldo_h_typ_voltages[] = {
+static const unsigned int ldo_h_typ_voltages[] = {
        2750000,
        1800000,
        1500000,
        1200000,
 };
 
-static const int ldo_k_typ_voltages[] = {
+static const unsigned int ldo_k_typ_voltages[] = {
        2750000,
        1800000,
 };
@@ -126,40 +118,27 @@ static struct ab3100_regulator
 ab3100_regulators[AB3100_NUM_REGULATORS] = {
        {
                .regreg = AB3100_LDO_A,
-               .fixed_voltage = LDO_A_VOLTAGE,
        },
        {
                .regreg = AB3100_LDO_C,
-               .fixed_voltage = LDO_C_VOLTAGE,
        },
        {
                .regreg = AB3100_LDO_D,
-               .fixed_voltage = LDO_D_VOLTAGE,
        },
        {
                .regreg = AB3100_LDO_E,
-               .typ_voltages = ldo_e_buck_typ_voltages,
-               .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
        },
        {
                .regreg = AB3100_LDO_F,
-               .typ_voltages = ldo_f_typ_voltages,
-               .voltages_len = ARRAY_SIZE(ldo_f_typ_voltages),
        },
        {
                .regreg = AB3100_LDO_G,
-               .typ_voltages = ldo_g_typ_voltages,
-               .voltages_len = ARRAY_SIZE(ldo_g_typ_voltages),
        },
        {
                .regreg = AB3100_LDO_H,
-               .typ_voltages = ldo_h_typ_voltages,
-               .voltages_len = ARRAY_SIZE(ldo_h_typ_voltages),
        },
        {
                .regreg = AB3100_LDO_K,
-               .typ_voltages = ldo_k_typ_voltages,
-               .voltages_len = ARRAY_SIZE(ldo_k_typ_voltages),
        },
        {
                .regreg = AB3100_LDO_EXT,
@@ -167,8 +146,6 @@ ab3100_regulators[AB3100_NUM_REGULATORS] = {
        },
        {
                .regreg = AB3100_BUCK,
-               .typ_voltages = ldo_e_buck_typ_voltages,
-               .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages),
        },
 };
 
@@ -178,7 +155,7 @@ ab3100_regulators[AB3100_NUM_REGULATORS] = {
  */
 static int ab3100_enable_regulator(struct regulator_dev *reg)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
+       struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
        int err;
        u8 regval;
 
@@ -209,7 +186,7 @@ static int ab3100_enable_regulator(struct regulator_dev *reg)
 
 static int ab3100_disable_regulator(struct regulator_dev *reg)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
+       struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
        int err;
        u8 regval;
 
@@ -242,7 +219,7 @@ static int ab3100_disable_regulator(struct regulator_dev *reg)
 
 static int ab3100_is_enabled_regulator(struct regulator_dev *reg)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
+       struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
        u8 regval;
        int err;
 
@@ -257,26 +234,12 @@ static int ab3100_is_enabled_regulator(struct regulator_dev *reg)
        return regval & AB3100_REG_ON_MASK;
 }
 
-static int ab3100_list_voltage_regulator(struct regulator_dev *reg,
-                                        unsigned selector)
-{
-       struct ab3100_regulator *abreg = reg->reg_data;
-
-       if (selector >= abreg->voltages_len)
-               return -EINVAL;
-       return abreg->typ_voltages[selector];
-}
-
 static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
+       struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
        u8 regval;
        int err;
 
-       /* Return the voltage for fixed regulators immediately */
-       if (abreg->fixed_voltage)
-               return abreg->fixed_voltage;
-
        /*
         * For variable types, read out setting and index into
         * supplied voltage list.
@@ -294,20 +257,20 @@ static int ab3100_get_voltage_regulator(struct regulator_dev *reg)
        regval &= 0xE0;
        regval >>= 5;
 
-       if (regval >= abreg->voltages_len) {
+       if (regval >= reg->desc->n_voltages) {
                dev_err(&reg->dev,
                        "regulator register %02x contains an illegal voltage setting\n",
                        abreg->regreg);
                return -EINVAL;
        }
 
-       return abreg->typ_voltages[regval];
+       return reg->desc->volt_table[regval];
 }
 
 static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg,
                                            unsigned selector)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
+       struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
        u8 regval;
        int err;
 
@@ -336,7 +299,7 @@ static int ab3100_set_voltage_regulator_sel(struct regulator_dev *reg,
 static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg,
                                                int uV)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
+       struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
        u8 regval;
        int err;
        int bestindex;
@@ -379,42 +342,22 @@ static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg,
  */
 static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
+       struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
 
        return abreg->plfdata->external_voltage;
 }
 
-static int ab3100_enable_time_regulator(struct regulator_dev *reg)
+static int ab3100_get_fixed_voltage_regulator(struct regulator_dev *reg)
 {
-       struct ab3100_regulator *abreg = reg->reg_data;
-
-       /* Per-regulator power on delay from spec */
-       switch (abreg->regreg) {
-       case AB3100_LDO_A: /* Fallthrough */
-       case AB3100_LDO_C: /* Fallthrough */
-       case AB3100_LDO_D: /* Fallthrough */
-       case AB3100_LDO_E: /* Fallthrough */
-       case AB3100_LDO_H: /* Fallthrough */
-       case AB3100_LDO_K:
-               return 200;
-       case AB3100_LDO_F:
-               return 600;
-       case AB3100_LDO_G:
-               return 400;
-       case AB3100_BUCK:
-               return 1000;
-       default:
-               break;
-       }
-       return 0;
+       return reg->desc->min_uV;
 }
 
 static struct regulator_ops regulator_ops_fixed = {
+       .list_voltage = regulator_list_voltage_linear,
        .enable      = ab3100_enable_regulator,
        .disable     = ab3100_disable_regulator,
        .is_enabled  = ab3100_is_enabled_regulator,
-       .get_voltage = ab3100_get_voltage_regulator,
-       .enable_time = ab3100_enable_time_regulator,
+       .get_voltage = ab3100_get_fixed_voltage_regulator,
 };
 
 static struct regulator_ops regulator_ops_variable = {
@@ -423,8 +366,7 @@ static struct regulator_ops regulator_ops_variable = {
        .is_enabled  = ab3100_is_enabled_regulator,
        .get_voltage = ab3100_get_voltage_regulator,
        .set_voltage_sel = ab3100_set_voltage_regulator_sel,
-       .list_voltage = ab3100_list_voltage_regulator,
-       .enable_time = ab3100_enable_time_regulator,
+       .list_voltage = regulator_list_voltage_table,
 };
 
 static struct regulator_ops regulator_ops_variable_sleepable = {
@@ -434,8 +376,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = {
        .get_voltage = ab3100_get_voltage_regulator,
        .set_voltage_sel = ab3100_set_voltage_regulator_sel,
        .set_suspend_voltage = ab3100_set_suspend_voltage_regulator,
-       .list_voltage = ab3100_list_voltage_regulator,
-       .enable_time = ab3100_enable_time_regulator,
+       .list_voltage = regulator_list_voltage_table,
 };
 
 /*
@@ -457,62 +398,81 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .name = "LDO_A",
                .id   = AB3100_LDO_A,
                .ops  = &regulator_ops_fixed,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .min_uV = LDO_A_VOLTAGE,
+               .enable_time = 200,
        },
        {
                .name = "LDO_C",
                .id   = AB3100_LDO_C,
                .ops  = &regulator_ops_fixed,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .min_uV = LDO_C_VOLTAGE,
+               .enable_time = 200,
        },
        {
                .name = "LDO_D",
                .id   = AB3100_LDO_D,
                .ops  = &regulator_ops_fixed,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .min_uV = LDO_D_VOLTAGE,
+               .enable_time = 200,
        },
        {
                .name = "LDO_E",
                .id   = AB3100_LDO_E,
                .ops  = &regulator_ops_variable_sleepable,
                .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+               .volt_table = ldo_e_buck_typ_voltages,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .enable_time = 200,
        },
        {
                .name = "LDO_F",
                .id   = AB3100_LDO_F,
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_f_typ_voltages),
+               .volt_table = ldo_f_typ_voltages,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .enable_time = 600,
        },
        {
                .name = "LDO_G",
                .id   = AB3100_LDO_G,
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_g_typ_voltages),
+               .volt_table = ldo_g_typ_voltages,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .enable_time = 400,
        },
        {
                .name = "LDO_H",
                .id   = AB3100_LDO_H,
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_h_typ_voltages),
+               .volt_table = ldo_h_typ_voltages,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .enable_time = 200,
        },
        {
                .name = "LDO_K",
                .id   = AB3100_LDO_K,
                .ops  = &regulator_ops_variable,
                .n_voltages = ARRAY_SIZE(ldo_k_typ_voltages),
+               .volt_table = ldo_k_typ_voltages,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .enable_time = 200,
        },
        {
                .name = "LDO_EXT",
@@ -528,6 +488,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
+               .enable_time = 1000,
        },
 };
 
index a739f5ca936a878481f408d67e0a7edf8688a42e..13d424fc1c14c675958014846b48391ff468dec7 100644 (file)
@@ -30,9 +30,6 @@
  * @dev: device pointer
  * @desc: regulator description
  * @regulator_dev: regulator device
- * @max_uV: maximum voltage (for variable voltage supplies)
- * @min_uV: minimum voltage (for variable voltage supplies)
- * @fixed_uV: typical voltage (for fixed voltage supplies)
  * @update_bank: bank to control on/off
  * @update_reg: register to control on/off
  * @update_mask: mask to enable/disable regulator
  * @voltage_bank: bank to control regulator voltage
  * @voltage_reg: register to control regulator voltage
  * @voltage_mask: mask to control regulator voltage
- * @voltages: supported voltage table
- * @voltages_len: number of supported voltages for the regulator
  * @delay: startup/set voltage delay in us
  */
 struct ab8500_regulator_info {
        struct device           *dev;
        struct regulator_desc   desc;
        struct regulator_dev    *regulator;
-       int max_uV;
-       int min_uV;
-       int fixed_uV;
        u8 update_bank;
        u8 update_reg;
        u8 update_mask;
@@ -58,13 +50,11 @@ struct ab8500_regulator_info {
        u8 voltage_bank;
        u8 voltage_reg;
        u8 voltage_mask;
-       int const *voltages;
-       int voltages_len;
        unsigned int delay;
 };
 
 /* voltage tables for the vauxn/vintcore supplies */
-static const int ldo_vauxn_voltages[] = {
+static const unsigned int ldo_vauxn_voltages[] = {
        1100000,
        1200000,
        1300000,
@@ -83,7 +73,7 @@ static const int ldo_vauxn_voltages[] = {
        3300000,
 };
 
-static const int ldo_vaux3_voltages[] = {
+static const unsigned int ldo_vaux3_voltages[] = {
        1200000,
        1500000,
        1800000,
@@ -94,7 +84,7 @@ static const int ldo_vaux3_voltages[] = {
        2910000,
 };
 
-static const int ldo_vintcore_voltages[] = {
+static const unsigned int ldo_vintcore_voltages[] = {
        1200000,
        1225000,
        1250000,
@@ -185,25 +175,6 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
                return false;
 }
 
-static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
-       struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
-       if (info == NULL) {
-               dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
-               return -EINVAL;
-       }
-
-       /* return the uV for the fixed regulators */
-       if (info->fixed_uV)
-               return info->fixed_uV;
-
-       if (selector >= info->voltages_len)
-               return -EINVAL;
-
-       return info->voltages[selector];
-}
-
 static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
 {
        int ret, val;
@@ -279,14 +250,7 @@ static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
                                             unsigned int new_sel)
 {
        struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-       int ret;
 
-       /* If the regulator isn't on, it won't take time here */
-       ret = ab8500_regulator_is_enabled(rdev);
-       if (ret < 0)
-               return ret;
-       if (!ret)
-               return 0;
        return info->delay;
 }
 
@@ -296,21 +260,14 @@ static struct regulator_ops ab8500_regulator_ops = {
        .is_enabled     = ab8500_regulator_is_enabled,
        .get_voltage_sel = ab8500_regulator_get_voltage_sel,
        .set_voltage_sel = ab8500_regulator_set_voltage_sel,
-       .list_voltage   = ab8500_list_voltage,
+       .list_voltage   = regulator_list_voltage_table,
        .enable_time    = ab8500_regulator_enable_time,
        .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
 };
 
 static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
 {
-       struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
-       if (info == NULL) {
-               dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
-               return -EINVAL;
-       }
-
-       return info->fixed_uV;
+       return rdev->desc->min_uV;
 }
 
 static struct regulator_ops ab8500_regulator_fixed_ops = {
@@ -318,9 +275,8 @@ static struct regulator_ops ab8500_regulator_fixed_ops = {
        .disable        = ab8500_regulator_disable,
        .is_enabled     = ab8500_regulator_is_enabled,
        .get_voltage    = ab8500_fixed_get_voltage,
-       .list_voltage   = ab8500_list_voltage,
+       .list_voltage   = regulator_list_voltage_linear,
        .enable_time    = ab8500_regulator_enable_time,
-       .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
 };
 
 static struct ab8500_regulator_info
@@ -329,7 +285,7 @@ static struct ab8500_regulator_info
         * Variable Voltage Regulators
         *   name, min mV, max mV,
         *   update bank, reg, mask, enable val
-        *   volt bank, reg, mask, table, table length
+        *   volt bank, reg, mask
         */
        [AB8500_LDO_AUX1] = {
                .desc = {
@@ -339,9 +295,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_AUX1,
                        .owner          = THIS_MODULE,
                        .n_voltages     = ARRAY_SIZE(ldo_vauxn_voltages),
+                       .volt_table     = ldo_vauxn_voltages,
                },
-               .min_uV                 = 1100000,
-               .max_uV                 = 3300000,
                .update_bank            = 0x04,
                .update_reg             = 0x09,
                .update_mask            = 0x03,
@@ -349,8 +304,6 @@ static struct ab8500_regulator_info
                .voltage_bank           = 0x04,
                .voltage_reg            = 0x1f,
                .voltage_mask           = 0x0f,
-               .voltages               = ldo_vauxn_voltages,
-               .voltages_len           = ARRAY_SIZE(ldo_vauxn_voltages),
        },
        [AB8500_LDO_AUX2] = {
                .desc = {
@@ -360,9 +313,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_AUX2,
                        .owner          = THIS_MODULE,
                        .n_voltages     = ARRAY_SIZE(ldo_vauxn_voltages),
+                       .volt_table     = ldo_vauxn_voltages,
                },
-               .min_uV                 = 1100000,
-               .max_uV                 = 3300000,
                .update_bank            = 0x04,
                .update_reg             = 0x09,
                .update_mask            = 0x0c,
@@ -370,8 +322,6 @@ static struct ab8500_regulator_info
                .voltage_bank           = 0x04,
                .voltage_reg            = 0x20,
                .voltage_mask           = 0x0f,
-               .voltages               = ldo_vauxn_voltages,
-               .voltages_len           = ARRAY_SIZE(ldo_vauxn_voltages),
        },
        [AB8500_LDO_AUX3] = {
                .desc = {
@@ -381,9 +331,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_AUX3,
                        .owner          = THIS_MODULE,
                        .n_voltages     = ARRAY_SIZE(ldo_vaux3_voltages),
+                       .volt_table     = ldo_vaux3_voltages,
                },
-               .min_uV                 = 1100000,
-               .max_uV                 = 3300000,
                .update_bank            = 0x04,
                .update_reg             = 0x0a,
                .update_mask            = 0x03,
@@ -391,8 +340,6 @@ static struct ab8500_regulator_info
                .voltage_bank           = 0x04,
                .voltage_reg            = 0x21,
                .voltage_mask           = 0x07,
-               .voltages               = ldo_vaux3_voltages,
-               .voltages_len           = ARRAY_SIZE(ldo_vaux3_voltages),
        },
        [AB8500_LDO_INTCORE] = {
                .desc = {
@@ -402,9 +349,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_INTCORE,
                        .owner          = THIS_MODULE,
                        .n_voltages     = ARRAY_SIZE(ldo_vintcore_voltages),
+                       .volt_table     = ldo_vintcore_voltages,
                },
-               .min_uV                 = 1100000,
-               .max_uV                 = 3300000,
                .update_bank            = 0x03,
                .update_reg             = 0x80,
                .update_mask            = 0x44,
@@ -412,8 +358,6 @@ static struct ab8500_regulator_info
                .voltage_bank           = 0x03,
                .voltage_reg            = 0x80,
                .voltage_mask           = 0x38,
-               .voltages               = ldo_vintcore_voltages,
-               .voltages_len           = ARRAY_SIZE(ldo_vintcore_voltages),
        },
 
        /*
@@ -429,9 +373,9 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_TVOUT,
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
+                       .min_uV         = 2000000,
                },
                .delay                  = 10000,
-               .fixed_uV               = 2000000,
                .update_bank            = 0x03,
                .update_reg             = 0x80,
                .update_mask            = 0x82,
@@ -445,8 +389,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_USB,
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
+                       .min_uV         = 3300000,
                },
-               .fixed_uV               = 3300000,
                .update_bank            = 0x03,
                .update_reg             = 0x82,
                .update_mask            = 0x03,
@@ -460,8 +404,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_AUDIO,
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
+                       .min_uV         = 2000000,
                },
-               .fixed_uV               = 2000000,
                .update_bank            = 0x03,
                .update_reg             = 0x83,
                .update_mask            = 0x02,
@@ -475,8 +419,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_ANAMIC1,
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
+                       .min_uV         = 2050000,
                },
-               .fixed_uV               = 2050000,
                .update_bank            = 0x03,
                .update_reg             = 0x83,
                .update_mask            = 0x08,
@@ -490,8 +434,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_ANAMIC2,
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
+                       .min_uV         = 2050000,
                },
-               .fixed_uV               = 2050000,
                .update_bank            = 0x03,
                .update_reg             = 0x83,
                .update_mask            = 0x10,
@@ -505,8 +449,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_DMIC,
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
+                       .min_uV         = 1800000,
                },
-               .fixed_uV               = 1800000,
                .update_bank            = 0x03,
                .update_reg             = 0x83,
                .update_mask            = 0x04,
@@ -520,8 +464,8 @@ static struct ab8500_regulator_info
                        .id             = AB8500_LDO_ANA,
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
+                       .min_uV         = 1200000,
                },
-               .fixed_uV               = 1200000,
                .update_bank            = 0x04,
                .update_reg             = 0x06,
                .update_mask            = 0x0c,
@@ -769,9 +713,7 @@ static __devinit int ab8500_regulator_register(struct platform_device *pdev,
                if (info->desc.id == AB8500_LDO_AUX3) {
                        info->desc.n_voltages =
                                ARRAY_SIZE(ldo_vauxn_voltages);
-                       info->voltages = ldo_vauxn_voltages;
-                       info->voltages_len =
-                               ARRAY_SIZE(ldo_vauxn_voltages);
+                       info->desc.volt_table = ldo_vauxn_voltages;
                        info->voltage_mask = 0xf;
                }
        }
index 46d05f38baf8ee9bbc1cf9b7e1cd80c59651fafe..f123f7e3b7525acd164ed639e022f25dc46711cf 100644 (file)
@@ -89,9 +89,12 @@ static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int
        unsigned short data;
        int ret;
 
-       if (min_uA > chip->max_uA || min_uA < chip->min_uA)
-               return -EINVAL;
-       if (max_uA > chip->max_uA || max_uA < chip->min_uA)
+       if (min_uA < chip->min_uA)
+               min_uA = chip->min_uA;
+       if (max_uA > chip->max_uA)
+               max_uA = chip->max_uA;
+
+       if (min_uA > chip->max_uA || max_uA < chip->min_uA)
                return -EINVAL;
 
        selector = DIV_ROUND_UP((min_uA - chip->min_uA) * chip->current_level,
index e82e7eaac0f18fd2a50ba3d5506c5620e3e50183..e9c2085f9dfbe0993c6931c573efb52a660f06a0 100644 (file)
@@ -43,33 +43,15 @@ struct anatop_regulator {
        struct regulator_init_data *initdata;
 };
 
-static int anatop_set_voltage(struct regulator_dev *reg, int min_uV,
-                                 int max_uV, unsigned *selector)
+static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
 {
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-       u32 val, sel, mask;
-       int uv;
-
-       uv = min_uV;
-       dev_dbg(&reg->dev, "%s: uv %d, min %d, max %d\n", __func__,
-               uv, anatop_reg->min_voltage,
-               anatop_reg->max_voltage);
-
-       if (uv < anatop_reg->min_voltage) {
-               if (max_uV > anatop_reg->min_voltage)
-                       uv = anatop_reg->min_voltage;
-               else
-                       return -EINVAL;
-       }
+       u32 val, mask;
 
        if (!anatop_reg->control_reg)
                return -ENOTSUPP;
 
-       sel = DIV_ROUND_UP(uv - anatop_reg->min_voltage, 25000);
-       if (sel * 25000 + anatop_reg->min_voltage > anatop_reg->max_voltage)
-               return -EINVAL;
-       val = anatop_reg->min_bit_val + sel;
-       *selector = sel;
+       val = anatop_reg->min_bit_val + selector;
        dev_dbg(&reg->dev, "%s: calculated val %d\n", __func__, val);
        mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
                anatop_reg->vol_bit_shift;
@@ -94,21 +76,11 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg)
        return val - anatop_reg->min_bit_val;
 }
 
-static int anatop_list_voltage(struct regulator_dev *reg, unsigned selector)
-{
-       struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-       int uv;
-
-       uv = anatop_reg->min_voltage + selector * 25000;
-       dev_dbg(&reg->dev, "vddio = %d, selector = %u\n", uv, selector);
-
-       return uv;
-}
-
 static struct regulator_ops anatop_rops = {
-       .set_voltage     = anatop_set_voltage,
+       .set_voltage_sel = anatop_set_voltage_sel,
        .get_voltage_sel = anatop_get_voltage_sel,
-       .list_voltage    = anatop_list_voltage,
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
 };
 
 static int __devinit anatop_regulator_probe(struct platform_device *pdev)
@@ -176,6 +148,8 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev)
 
        rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage)
                / 25000 + 1;
+       rdesc->min_uV = sreg->min_voltage;
+       rdesc->uV_step = 25000;
 
        config.dev = &pdev->dev;
        config.init_data = initdata;
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
new file mode 100644 (file)
index 0000000..c8f95c0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * arizona-ldo1.c  --  LDO1 supply for Arizona devices
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+struct arizona_ldo1 {
+       struct regulator_dev *regulator;
+       struct arizona *arizona;
+
+       struct regulator_consumer_supply supply;
+       struct regulator_init_data init_data;
+};
+
+static struct regulator_ops arizona_ldo1_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc arizona_ldo1 = {
+       .name = "LDO1",
+       .supply_name = "LDOVDD",
+       .type = REGULATOR_VOLTAGE,
+       .ops = &arizona_ldo1_ops,
+
+       .vsel_reg = ARIZONA_LDO1_CONTROL_1,
+       .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
+       .min_uV = 900000,
+       .uV_step = 50000,
+       .n_voltages = 7,
+
+       .owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data arizona_ldo1_default = {
+       .constraints = {
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+       .num_consumer_supplies = 1,
+};
+
+static __devinit int arizona_ldo1_probe(struct platform_device *pdev)
+{
+       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = { };
+       struct arizona_ldo1 *ldo1;
+       int ret;
+
+       ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL);
+       if (ldo1 == NULL) {
+               dev_err(&pdev->dev, "Unable to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       ldo1->arizona = arizona;
+
+       /*
+        * Since the chip usually supplies itself we provide some
+        * default init_data for it.  This will be overridden with
+        * platform data if provided.
+        */
+       ldo1->init_data = arizona_ldo1_default;
+       ldo1->init_data.consumer_supplies = &ldo1->supply;
+       ldo1->supply.supply = "DCVDD";
+       ldo1->supply.dev_name = dev_name(arizona->dev);
+
+       config.dev = arizona->dev;
+       config.driver_data = ldo1;
+       config.regmap = arizona->regmap;
+       config.ena_gpio = arizona->pdata.ldoena;
+
+       if (arizona->pdata.ldo1)
+               config.init_data = arizona->pdata.ldo1;
+       else
+               config.init_data = &ldo1->init_data;
+
+       ldo1->regulator = regulator_register(&arizona_ldo1, &config);
+       if (IS_ERR(ldo1->regulator)) {
+               ret = PTR_ERR(ldo1->regulator);
+               dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n",
+                       ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, ldo1);
+
+       return 0;
+}
+
+static __devexit int arizona_ldo1_remove(struct platform_device *pdev)
+{
+       struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev);
+
+       regulator_unregister(ldo1->regulator);
+
+       return 0;
+}
+
+static struct platform_driver arizona_ldo1_driver = {
+       .probe = arizona_ldo1_probe,
+       .remove = __devexit_p(arizona_ldo1_remove),
+       .driver         = {
+               .name   = "arizona-ldo1",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(arizona_ldo1_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Arizona LDO1 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:arizona-ldo1");
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
new file mode 100644 (file)
index 0000000..450a069
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * arizona-micsupp.c  --  Microphone supply for Arizona devices
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/pdata.h>
+#include <linux/mfd/arizona/registers.h>
+
+#define ARIZONA_MICSUPP_MAX_SELECTOR 0x1f
+
+struct arizona_micsupp {
+       struct regulator_dev *regulator;
+       struct arizona *arizona;
+
+       struct regulator_consumer_supply supply;
+       struct regulator_init_data init_data;
+};
+
+static int arizona_micsupp_list_voltage(struct regulator_dev *rdev,
+                                       unsigned int selector)
+{
+       if (selector > ARIZONA_MICSUPP_MAX_SELECTOR)
+               return -EINVAL;
+
+       if (selector == ARIZONA_MICSUPP_MAX_SELECTOR)
+               return 3300000;
+       else
+               return (selector * 50000) + 1700000;
+}
+
+static int arizona_micsupp_map_voltage(struct regulator_dev *rdev,
+                                      int min_uV, int max_uV)
+{
+       unsigned int voltage;
+       int selector;
+
+       if (min_uV < 1700000)
+               min_uV = 1700000;
+
+       if (min_uV > 3200000)
+               selector = ARIZONA_MICSUPP_MAX_SELECTOR;
+       else
+               selector = DIV_ROUND_UP(min_uV - 1700000, 50000);
+
+       if (selector < 0)
+               return -EINVAL;
+
+       voltage = arizona_micsupp_list_voltage(rdev, selector);
+       if (voltage < min_uV || voltage > max_uV)
+               return -EINVAL;
+
+       return selector;
+}
+
+static struct regulator_ops arizona_micsupp_ops = {
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+
+       .list_voltage = arizona_micsupp_list_voltage,
+       .map_voltage = arizona_micsupp_map_voltage,
+
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc arizona_micsupp = {
+       .name = "MICVDD",
+       .supply_name = "CPVDD",
+       .type = REGULATOR_VOLTAGE,
+       .n_voltages = ARIZONA_MICSUPP_MAX_SELECTOR + 1,
+       .ops = &arizona_micsupp_ops,
+
+       .vsel_reg = ARIZONA_LDO2_CONTROL_1,
+       .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
+       .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
+       .enable_mask = ARIZONA_CPMIC_ENA,
+
+       .owner = THIS_MODULE,
+};
+
+static const struct regulator_init_data arizona_micsupp_default = {
+       .constraints = {
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS |
+                               REGULATOR_CHANGE_VOLTAGE,
+               .min_uV = 1700000,
+               .max_uV = 3300000,
+       },
+
+       .num_consumer_supplies = 1,
+};
+
+static __devinit int arizona_micsupp_probe(struct platform_device *pdev)
+{
+       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+       struct regulator_config config = { };
+       struct arizona_micsupp *micsupp;
+       int ret;
+
+       micsupp = devm_kzalloc(&pdev->dev, sizeof(*micsupp), GFP_KERNEL);
+       if (micsupp == NULL) {
+               dev_err(&pdev->dev, "Unable to allocate private data\n");
+               return -ENOMEM;
+       }
+
+       micsupp->arizona = arizona;
+
+       /*
+        * Since the chip usually supplies itself we provide some
+        * default init_data for it.  This will be overridden with
+        * platform data if provided.
+        */
+       micsupp->init_data = arizona_micsupp_default;
+       micsupp->init_data.consumer_supplies = &micsupp->supply;
+       micsupp->supply.supply = "MICVDD";
+       micsupp->supply.dev_name = dev_name(arizona->dev);
+
+       config.dev = arizona->dev;
+       config.driver_data = micsupp;
+       config.regmap = arizona->regmap;
+
+       if (arizona->pdata.micvdd)
+               config.init_data = arizona->pdata.micvdd;
+       else
+               config.init_data = &micsupp->init_data;
+
+       /* Default to regulated mode until the API supports bypass */
+       regmap_update_bits(arizona->regmap, ARIZONA_MIC_CHARGE_PUMP_1,
+                          ARIZONA_CPMIC_BYPASS, 0);
+
+       micsupp->regulator = regulator_register(&arizona_micsupp, &config);
+       if (IS_ERR(micsupp->regulator)) {
+               ret = PTR_ERR(micsupp->regulator);
+               dev_err(arizona->dev, "Failed to register mic supply: %d\n",
+                       ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, micsupp);
+
+       return 0;
+}
+
+static __devexit int arizona_micsupp_remove(struct platform_device *pdev)
+{
+       struct arizona_micsupp *micsupp = platform_get_drvdata(pdev);
+
+       regulator_unregister(micsupp->regulator);
+
+       return 0;
+}
+
+static struct platform_driver arizona_micsupp_driver = {
+       .probe = arizona_micsupp_probe,
+       .remove = __devexit_p(arizona_micsupp_remove),
+       .driver         = {
+               .name   = "arizona-micsupp",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(arizona_micsupp_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("Arizona microphone supply driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:arizona-micsupp");
index 09a737c868b573227d22226926a081f35a29e6b2..2e31dffbefe7e4707a93101b86efa85caea02d48 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/suspend.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
@@ -108,28 +109,6 @@ static const char *rdev_get_name(struct regulator_dev *rdev)
                return "";
 }
 
-/* gets the regulator for a given consumer device */
-static struct regulator *get_device_regulator(struct device *dev)
-{
-       struct regulator *regulator = NULL;
-       struct regulator_dev *rdev;
-
-       mutex_lock(&regulator_list_mutex);
-       list_for_each_entry(rdev, &regulator_list, list) {
-               mutex_lock(&rdev->mutex);
-               list_for_each_entry(regulator, &rdev->consumer_list, list) {
-                       if (regulator->dev == dev) {
-                               mutex_unlock(&rdev->mutex);
-                               mutex_unlock(&regulator_list_mutex);
-                               return regulator;
-                       }
-               }
-               mutex_unlock(&rdev->mutex);
-       }
-       mutex_unlock(&regulator_list_mutex);
-       return NULL;
-}
-
 /**
  * of_get_regulator - get a regulator device node based on supply name
  * @dev: Device pointer for the consumer (of regulator) device
@@ -303,18 +282,6 @@ static int regulator_check_drms(struct regulator_dev *rdev)
        return 0;
 }
 
-static ssize_t device_requested_uA_show(struct device *dev,
-                            struct device_attribute *attr, char *buf)
-{
-       struct regulator *regulator;
-
-       regulator = get_device_regulator(dev);
-       if (regulator == NULL)
-               return 0;
-
-       return sprintf(buf, "%d\n", regulator->uA_load);
-}
-
 static ssize_t regulator_uV_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
@@ -427,6 +394,9 @@ static ssize_t regulator_status_show(struct device *dev,
        case REGULATOR_STATUS_STANDBY:
                label = "standby";
                break;
+       case REGULATOR_STATUS_UNDEFINED:
+               label = "undefined";
+               break;
        default:
                return -ERANGE;
        }
@@ -967,6 +937,14 @@ static int set_machine_constraints(struct regulator_dev *rdev,
                }
        }
 
+       if (rdev->constraints->ramp_delay && ops->set_ramp_delay) {
+               ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
+               if (ret < 0) {
+                       rdev_err(rdev, "failed to set ramp_delay\n");
+                       goto out;
+               }
+       }
+
        print_constraints(rdev);
        return 0;
 out:
@@ -1097,48 +1075,29 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
        list_add(&regulator->list, &rdev->consumer_list);
 
        if (dev) {
-               /* create a 'requested_microamps_name' sysfs entry */
-               size = scnprintf(buf, REG_STR_SIZE,
-                                "microamps_requested_%s-%s",
-                                dev_name(dev), supply_name);
-               if (size >= REG_STR_SIZE)
-                       goto overflow_err;
-
                regulator->dev = dev;
-               sysfs_attr_init(&regulator->dev_attr.attr);
-               regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL);
-               if (regulator->dev_attr.attr.name == NULL)
-                       goto attr_name_err;
-
-               regulator->dev_attr.attr.mode = 0444;
-               regulator->dev_attr.show = device_requested_uA_show;
-               err = device_create_file(dev, &regulator->dev_attr);
-               if (err < 0) {
-                       rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n");
-                       goto attr_name_err;
-               }
 
-               /* also add a link to the device sysfs entry */
+               /* Add a link to the device sysfs entry */
                size = scnprintf(buf, REG_STR_SIZE, "%s-%s",
                                 dev->kobj.name, supply_name);
                if (size >= REG_STR_SIZE)
-                       goto attr_err;
+                       goto overflow_err;
 
                regulator->supply_name = kstrdup(buf, GFP_KERNEL);
                if (regulator->supply_name == NULL)
-                       goto attr_err;
+                       goto overflow_err;
 
                err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj,
                                        buf);
                if (err) {
                        rdev_warn(rdev, "could not add device link %s err %d\n",
                                  dev->kobj.name, err);
-                       goto link_name_err;
+                       /* non-fatal */
                }
        } else {
                regulator->supply_name = kstrdup(supply_name, GFP_KERNEL);
                if (regulator->supply_name == NULL)
-                       goto attr_err;
+                       goto overflow_err;
        }
 
        regulator->debugfs = debugfs_create_dir(regulator->supply_name,
@@ -1165,12 +1124,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
 
        mutex_unlock(&rdev->mutex);
        return regulator;
-link_name_err:
-       kfree(regulator->supply_name);
-attr_err:
-       device_remove_file(regulator->dev, &regulator->dev_attr);
-attr_name_err:
-       kfree(regulator->dev_attr.attr.name);
 overflow_err:
        list_del(&regulator->list);
        kfree(regulator);
@@ -1181,7 +1134,7 @@ overflow_err:
 static int _regulator_get_enable_time(struct regulator_dev *rdev)
 {
        if (!rdev->desc->ops->enable_time)
-               return 0;
+               return rdev->desc->enable_time;
        return rdev->desc->ops->enable_time(rdev);
 }
 
@@ -1420,11 +1373,8 @@ void regulator_put(struct regulator *regulator)
        debugfs_remove_recursive(regulator->debugfs);
 
        /* remove any sysfs entries */
-       if (regulator->dev) {
+       if (regulator->dev)
                sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
-               device_remove_file(regulator->dev, &regulator->dev_attr);
-               kfree(regulator->dev_attr.attr.name);
-       }
        kfree(regulator->supply_name);
        list_del(&regulator->list);
        kfree(regulator);
@@ -1459,19 +1409,61 @@ void devm_regulator_put(struct regulator *regulator)
 {
        int rc;
 
-       rc = devres_destroy(regulator->dev, devm_regulator_release,
+       rc = devres_release(regulator->dev, devm_regulator_release,
                            devm_regulator_match, regulator);
-       if (rc == 0)
-               regulator_put(regulator);
-       else
+       if (rc != 0)
                WARN_ON(rc);
 }
 EXPORT_SYMBOL_GPL(devm_regulator_put);
 
+static int _regulator_do_enable(struct regulator_dev *rdev)
+{
+       int ret, delay;
+
+       /* Query before enabling in case configuration dependent.  */
+       ret = _regulator_get_enable_time(rdev);
+       if (ret >= 0) {
+               delay = ret;
+       } else {
+               rdev_warn(rdev, "enable_time() failed: %d\n", ret);
+               delay = 0;
+       }
+
+       trace_regulator_enable(rdev_get_name(rdev));
+
+       if (rdev->ena_gpio) {
+               gpio_set_value_cansleep(rdev->ena_gpio,
+                                       !rdev->ena_gpio_invert);
+               rdev->ena_gpio_state = 1;
+       } else if (rdev->desc->ops->enable) {
+               ret = rdev->desc->ops->enable(rdev);
+               if (ret < 0)
+                       return ret;
+       } else {
+               return -EINVAL;
+       }
+
+       /* Allow the regulator to ramp; it would be useful to extend
+        * this for bulk operations so that the regulators can ramp
+        * together.  */
+       trace_regulator_enable_delay(rdev_get_name(rdev));
+
+       if (delay >= 1000) {
+               mdelay(delay / 1000);
+               udelay(delay % 1000);
+       } else if (delay) {
+               udelay(delay);
+       }
+
+       trace_regulator_enable_complete(rdev_get_name(rdev));
+
+       return 0;
+}
+
 /* locks held by regulator_enable() */
 static int _regulator_enable(struct regulator_dev *rdev)
 {
-       int ret, delay;
+       int ret;
 
        /* check voltage and requested load before enabling */
        if (rdev->constraints &&
@@ -1485,40 +1477,10 @@ static int _regulator_enable(struct regulator_dev *rdev)
                        if (!_regulator_can_change_status(rdev))
                                return -EPERM;
 
-                       if (!rdev->desc->ops->enable)
-                               return -EINVAL;
-
-                       /* Query before enabling in case configuration
-                        * dependent.  */
-                       ret = _regulator_get_enable_time(rdev);
-                       if (ret >= 0) {
-                               delay = ret;
-                       } else {
-                               rdev_warn(rdev, "enable_time() failed: %d\n",
-                                          ret);
-                               delay = 0;
-                       }
-
-                       trace_regulator_enable(rdev_get_name(rdev));
-
-                       /* Allow the regulator to ramp; it would be useful
-                        * to extend this for bulk operations so that the
-                        * regulators can ramp together.  */
-                       ret = rdev->desc->ops->enable(rdev);
+                       ret = _regulator_do_enable(rdev);
                        if (ret < 0)
                                return ret;
 
-                       trace_regulator_enable_delay(rdev_get_name(rdev));
-
-                       if (delay >= 1000) {
-                               mdelay(delay / 1000);
-                               udelay(delay % 1000);
-                       } else if (delay) {
-                               udelay(delay);
-                       }
-
-                       trace_regulator_enable_complete(rdev_get_name(rdev));
-
                } else if (ret < 0) {
                        rdev_err(rdev, "is_enabled() failed: %d\n", ret);
                        return ret;
@@ -1567,6 +1529,30 @@ int regulator_enable(struct regulator *regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_enable);
 
+static int _regulator_do_disable(struct regulator_dev *rdev)
+{
+       int ret;
+
+       trace_regulator_disable(rdev_get_name(rdev));
+
+       if (rdev->ena_gpio) {
+               gpio_set_value_cansleep(rdev->ena_gpio,
+                                       rdev->ena_gpio_invert);
+               rdev->ena_gpio_state = 0;
+
+       } else if (rdev->desc->ops->disable) {
+               ret = rdev->desc->ops->disable(rdev);
+               if (ret != 0)
+                       return ret;
+       }
+
+       trace_regulator_disable_complete(rdev_get_name(rdev));
+
+       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+                            NULL);
+       return 0;
+}
+
 /* locks held by regulator_disable() */
 static int _regulator_disable(struct regulator_dev *rdev)
 {
@@ -1581,20 +1567,12 @@ static int _regulator_disable(struct regulator_dev *rdev)
            (rdev->constraints && !rdev->constraints->always_on)) {
 
                /* we are last user */
-               if (_regulator_can_change_status(rdev) &&
-                   rdev->desc->ops->disable) {
-                       trace_regulator_disable(rdev_get_name(rdev));
-
-                       ret = rdev->desc->ops->disable(rdev);
+               if (_regulator_can_change_status(rdev)) {
+                       ret = _regulator_do_disable(rdev);
                        if (ret < 0) {
                                rdev_err(rdev, "failed to disable\n");
                                return ret;
                        }
-
-                       trace_regulator_disable_complete(rdev_get_name(rdev));
-
-                       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
-                                            NULL);
                }
 
                rdev->use_count = 0;
@@ -1812,6 +1790,10 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap);
 
 static int _regulator_is_enabled(struct regulator_dev *rdev)
 {
+       /* A GPIO control always takes precedence */
+       if (rdev->ena_gpio)
+               return rdev->ena_gpio_state;
+
        /* If we don't know then assume that the regulator is always on */
        if (!rdev->desc->ops->is_enabled)
                return 1;
@@ -1882,6 +1864,31 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
 
+/**
+ * regulator_list_voltage_table - List voltages with table based mapping
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with table based mapping between voltages and
+ * selectors can set volt_table in the regulator descriptor
+ * and then use this function as their list_voltage() operation.
+ */
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+                                unsigned int selector)
+{
+       if (!rdev->desc->volt_table) {
+               BUG_ON(!rdev->desc->volt_table);
+               return -EINVAL;
+       }
+
+       if (selector >= rdev->desc->n_voltages)
+               return -EINVAL;
+
+       return rdev->desc->volt_table[selector];
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
+
 /**
  * regulator_list_voltage - enumerate supported voltages
  * @regulator: regulator source
@@ -1928,8 +1935,18 @@ EXPORT_SYMBOL_GPL(regulator_list_voltage);
 int regulator_is_supported_voltage(struct regulator *regulator,
                                   int min_uV, int max_uV)
 {
+       struct regulator_dev *rdev = regulator->rdev;
        int i, voltages, ret;
 
+       /* If we can't change voltage check the current voltage */
+       if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+               ret = regulator_get_voltage(regulator);
+               if (ret >= 0)
+                       return (min_uV >= ret && ret <= max_uV);
+               else
+                       return ret;
+       }
+
        ret = regulator_count_voltages(regulator);
        if (ret < 0)
                return ret;
@@ -2045,6 +2062,14 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev,
 {
        int ret, voltage;
 
+       /* Allow uV_step to be 0 for fixed voltage */
+       if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+               if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+
        if (!rdev->desc->uV_step) {
                BUG_ON(!rdev->desc->uV_step);
                return -EINVAL;
@@ -2071,7 +2096,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 {
        int ret;
        int delay = 0;
-       int best_val;
+       int best_val = 0;
        unsigned int selector;
        int old_selector = -1;
 
@@ -2084,7 +2109,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
         * If we can't obtain the old selector there is not enough
         * info to call set_voltage_time_sel().
         */
-       if (rdev->desc->ops->set_voltage_time_sel &&
+       if (_regulator_is_enabled(rdev) &&
+           rdev->desc->ops->set_voltage_time_sel &&
            rdev->desc->ops->get_voltage_sel) {
                old_selector = rdev->desc->ops->get_voltage_sel(rdev);
                if (old_selector < 0)
@@ -2094,29 +2120,45 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
        if (rdev->desc->ops->set_voltage) {
                ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
                                                   &selector);
+
+               if (ret >= 0) {
+                       if (rdev->desc->ops->list_voltage)
+                               best_val = rdev->desc->ops->list_voltage(rdev,
+                                                                        selector);
+                       else
+                               best_val = _regulator_get_voltage(rdev);
+               }
+
        } else if (rdev->desc->ops->set_voltage_sel) {
-               if (rdev->desc->ops->map_voltage)
+               if (rdev->desc->ops->map_voltage) {
                        ret = rdev->desc->ops->map_voltage(rdev, min_uV,
                                                           max_uV);
-               else
-                       ret = regulator_map_voltage_iterate(rdev, min_uV,
-                                                           max_uV);
+               } else {
+                       if (rdev->desc->ops->list_voltage ==
+                           regulator_list_voltage_linear)
+                               ret = regulator_map_voltage_linear(rdev,
+                                                               min_uV, max_uV);
+                       else
+                               ret = regulator_map_voltage_iterate(rdev,
+                                                               min_uV, max_uV);
+               }
 
                if (ret >= 0) {
-                       selector = ret;
-                       ret = rdev->desc->ops->set_voltage_sel(rdev, ret);
+                       best_val = rdev->desc->ops->list_voltage(rdev, ret);
+                       if (min_uV <= best_val && max_uV >= best_val) {
+                               selector = ret;
+                               ret = rdev->desc->ops->set_voltage_sel(rdev,
+                                                                      ret);
+                       } else {
+                               ret = -EINVAL;
+                       }
                }
        } else {
                ret = -EINVAL;
        }
 
-       if (rdev->desc->ops->list_voltage)
-               best_val = rdev->desc->ops->list_voltage(rdev, selector);
-       else
-               best_val = -1;
-
        /* Call set_voltage_time_sel if successfully obtained old_selector */
-       if (ret == 0 && old_selector >= 0 &&
+       if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
            rdev->desc->ops->set_voltage_time_sel) {
 
                delay = rdev->desc->ops->set_voltage_time_sel(rdev,
@@ -2126,19 +2168,19 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                                  delay);
                        delay = 0;
                }
-       }
 
-       /* Insert any necessary delays */
-       if (delay >= 1000) {
-               mdelay(delay / 1000);
-               udelay(delay % 1000);
-       } else if (delay) {
-               udelay(delay);
+               /* Insert any necessary delays */
+               if (delay >= 1000) {
+                       mdelay(delay / 1000);
+                       udelay(delay % 1000);
+               } else if (delay) {
+                       udelay(delay);
+               }
        }
 
-       if (ret == 0)
+       if (ret == 0 && best_val >= 0)
                _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
-                                    NULL);
+                                    (void *)best_val);
 
        trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
 
@@ -2248,6 +2290,46 @@ int regulator_set_voltage_time(struct regulator *regulator,
 }
 EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
 
+/**
+ *regulator_set_voltage_time_sel - get raise/fall time
+ * @regulator: regulator source
+ * @old_selector: selector for starting voltage
+ * @new_selector: selector for target voltage
+ *
+ * Provided with the starting and target voltage selectors, this function
+ * returns time in microseconds required to rise or fall to this new voltage
+ *
+ * Drivers providing ramp_delay in regulation_constraints can use this as their
+ * set_voltage_time_sel() operation.
+ */
+int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+                                  unsigned int old_selector,
+                                  unsigned int new_selector)
+{
+       unsigned int ramp_delay = 0;
+       int old_volt, new_volt;
+
+       if (rdev->constraints->ramp_delay)
+               ramp_delay = rdev->constraints->ramp_delay;
+       else if (rdev->desc->ramp_delay)
+               ramp_delay = rdev->desc->ramp_delay;
+
+       if (ramp_delay == 0) {
+               rdev_warn(rdev, "ramp_delay not set\n");
+               return 0;
+       }
+
+       /* sanity check */
+       if (!rdev->desc->ops->list_voltage)
+               return -EINVAL;
+
+       old_volt = rdev->desc->ops->list_voltage(rdev, old_selector);
+       new_volt = rdev->desc->ops->list_voltage(rdev, new_selector);
+
+       return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel);
+
 /**
  * regulator_sync_voltage - re-apply last regulator output voltage
  * @regulator: regulator source
@@ -2519,9 +2601,12 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
 {
        struct regulator_dev *rdev = regulator->rdev;
        struct regulator *consumer;
-       int ret, output_uV, input_uV, total_uA_load = 0;
+       int ret, output_uV, input_uV = 0, total_uA_load = 0;
        unsigned int mode;
 
+       if (rdev->supply)
+               input_uV = regulator_get_voltage(rdev->supply);
+
        mutex_lock(&rdev->mutex);
 
        /*
@@ -2554,10 +2639,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
                goto out;
        }
 
-       /* get input voltage */
-       input_uV = 0;
-       if (rdev->supply)
-               input_uV = regulator_get_voltage(rdev->supply);
+       /* No supply? Use constraint voltage */
        if (input_uV <= 0)
                input_uV = rdev->constraints->input_uV;
        if (input_uV <= 0) {
@@ -2628,7 +2710,7 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data)
 {
        /* call rdev chain first */
-       blocking_notifier_call_chain(&rdev->notifier, event, NULL);
+       blocking_notifier_call_chain(&rdev->notifier, event, data);
 }
 
 /**
@@ -2909,10 +2991,10 @@ int regulator_mode_to_status(unsigned int mode)
                return REGULATOR_STATUS_NORMAL;
        case REGULATOR_MODE_IDLE:
                return REGULATOR_STATUS_IDLE;
-       case REGULATOR_STATUS_STANDBY:
+       case REGULATOR_MODE_STANDBY:
                return REGULATOR_STATUS_STANDBY;
        default:
-               return 0;
+               return REGULATOR_STATUS_UNDEFINED;
        }
 }
 EXPORT_SYMBOL_GPL(regulator_mode_to_status);
@@ -3105,7 +3187,10 @@ regulator_register(const struct regulator_desc *regulator_desc,
        rdev->reg_data = config->driver_data;
        rdev->owner = regulator_desc->owner;
        rdev->desc = regulator_desc;
-       rdev->regmap = config->regmap;
+       if (config->regmap)
+               rdev->regmap = config->regmap;
+       else
+               rdev->regmap = dev_get_regmap(dev, NULL);
        INIT_LIST_HEAD(&rdev->consumer_list);
        INIT_LIST_HEAD(&rdev->list);
        BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
@@ -3132,6 +3217,26 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        dev_set_drvdata(&rdev->dev, rdev);
 
+       if (config->ena_gpio) {
+               ret = gpio_request_one(config->ena_gpio,
+                                      GPIOF_DIR_OUT | config->ena_gpio_flags,
+                                      rdev_get_name(rdev));
+               if (ret != 0) {
+                       rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
+                                config->ena_gpio, ret);
+                       goto clean;
+               }
+
+               rdev->ena_gpio = config->ena_gpio;
+               rdev->ena_gpio_invert = config->ena_gpio_invert;
+
+               if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
+                       rdev->ena_gpio_state = 1;
+
+               if (rdev->ena_gpio_invert)
+                       rdev->ena_gpio_state = !rdev->ena_gpio_state;
+       }
+
        /* set regulator constraints */
        if (init_data)
                constraints = &init_data->constraints;
@@ -3200,6 +3305,8 @@ unset_supplies:
 scrub:
        if (rdev->supply)
                regulator_put(rdev->supply);
+       if (rdev->ena_gpio)
+               gpio_free(rdev->ena_gpio);
        kfree(rdev->constraints);
        device_unregister(&rdev->dev);
        /* device core frees rdev */
@@ -3233,6 +3340,8 @@ void regulator_unregister(struct regulator_dev *rdev)
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        kfree(rdev->constraints);
+       if (rdev->ena_gpio)
+               gpio_free(rdev->ena_gpio);
        device_unregister(&rdev->dev);
        mutex_unlock(&regulator_list_mutex);
 }
@@ -3472,6 +3581,15 @@ static int __init regulator_init_complete(void)
        struct regulation_constraints *c;
        int enabled, ret;
 
+       /*
+        * Since DT doesn't provide an idiomatic mechanism for
+        * enabling full constraints and since it's much more natural
+        * with DT to provide them just assume that a DT enabled
+        * system has full constraints.
+        */
+       if (of_have_populated_dt())
+               has_full_constraints = true;
+
        mutex_lock(&regulator_list_mutex);
 
        /* If we have a full configuration then disable any regulators
index 1005f5f7e603e8f361718302d070adcfc80a236d..36c5b92fe0af26487cb093234800d534061c41f6 100644 (file)
@@ -107,6 +107,9 @@ static int da903x_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
        struct device *da9034_dev = to_da903x_dev(rdev);
        uint8_t val, mask;
 
+       if (rdev->desc->n_voltages == 1)
+               return -EINVAL;
+
        val = selector << info->vol_shift;
        mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
 
@@ -120,6 +123,9 @@ static int da903x_get_voltage_sel(struct regulator_dev *rdev)
        uint8_t val, mask;
        int ret;
 
+       if (rdev->desc->n_voltages == 1)
+               return 0;
+
        ret = da903x_read(da9034_dev, info->vol_reg, &val);
        if (ret)
                return ret;
index 88976d8d44edd1af9d906ca8e2acea259ab46a37..903299cf15cfe8c9716d583fc3c49d76d4ac2d04 100644 (file)
@@ -405,12 +405,12 @@ static int __devinit da9052_regulator_probe(struct platform_device *pdev)
                if (!nproot)
                        return -ENODEV;
 
-               for (np = of_get_next_child(nproot, NULL); np;
-                    np = of_get_next_child(nproot, np)) {
+               for_each_child_of_node(nproot, np) {
                        if (!of_node_cmp(np->name,
                                         regulator->info->reg_desc.name)) {
                                config.init_data = of_get_regulator_init_data(
                                        &pdev->dev, np);
+                               config.of_node = np;
                                break;
                        }
                }
index cacd33c9d042fae944b3684811ad1cdc20ef5268..f9d027992aae119b466efa9ba0ac087ce8739074 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
@@ -13,17 +14,20 @@ static void regulator_fixed_release(struct device *dev)
 {
        struct fixed_regulator_data *data = container_of(dev,
                        struct fixed_regulator_data, pdev.dev);
+       kfree(data->cfg.supply_name);
        kfree(data);
 }
 
 /**
- * regulator_register_fixed - register a no-op fixed regulator
+ * regulator_register_fixed_name - register a no-op fixed regulator
  * @id: platform device id
+ * @name: name to be used for the regulator
  * @supplies: consumers for this regulator
  * @num_supplies: number of consumers
+ * @uv: voltage in microvolts
  */
-struct platform_device *regulator_register_fixed(int id,
-               struct regulator_consumer_supply *supplies, int num_supplies)
+struct platform_device *regulator_register_always_on(int id, const char *name,
+       struct regulator_consumer_supply *supplies, int num_supplies, int uv)
 {
        struct fixed_regulator_data *data;
 
@@ -31,8 +35,13 @@ struct platform_device *regulator_register_fixed(int id,
        if (!data)
                return NULL;
 
-       data->cfg.supply_name = "fixed-dummy";
-       data->cfg.microvolts = 0;
+       data->cfg.supply_name = kstrdup(name, GFP_KERNEL);
+       if (!data->cfg.supply_name) {
+               kfree(data);
+               return NULL;
+       }
+
+       data->cfg.microvolts = uv;
        data->cfg.gpio = -EINVAL;
        data->cfg.enabled_at_boot = 1;
        data->cfg.init_data = &data->init_data;
index f09fe7b20e82282e9f68957c1c7b56cad426544e..185468c4d38fcbe691c7842ca9a0f50068ca5e25 100644 (file)
@@ -35,10 +35,6 @@ struct fixed_voltage_data {
        struct regulator_desc desc;
        struct regulator_dev *dev;
        int microvolts;
-       int gpio;
-       unsigned startup_delay;
-       bool enable_high;
-       bool is_enabled;
 };
 
 
@@ -61,11 +57,11 @@ of_get_fixed_voltage_config(struct device *dev)
        config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config),
                                                                 GFP_KERNEL);
        if (!config)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        config->init_data = of_get_regulator_init_data(dev, dev->of_node);
        if (!config->init_data)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        init_data = config->init_data;
        init_data->constraints.apply_uV = 0;
@@ -76,13 +72,26 @@ of_get_fixed_voltage_config(struct device *dev)
        } else {
                dev_err(dev,
                         "Fixed regulator specified with variable voltages\n");
-               return NULL;
+               return ERR_PTR(-EINVAL);
        }
 
        if (init_data->constraints.boot_on)
                config->enabled_at_boot = true;
 
        config->gpio = of_get_named_gpio(np, "gpio", 0);
+       /*
+        * of_get_named_gpio() currently returns ENODEV rather than
+        * EPROBE_DEFER. This code attempts to be compatible with both
+        * for now; the ENODEV check can be removed once the API is fixed.
+        * of_get_named_gpio() doesn't differentiate between a missing
+        * property (which would be fine here, since the GPIO is optional)
+        * and some other error. Patches have been posted for both issues.
+        * Once they are check in, we should replace this with:
+        * if (config->gpio < 0 && config->gpio != -ENOENT)
+        */
+       if ((config->gpio == -ENODEV) || (config->gpio == -EPROBE_DEFER))
+               return ERR_PTR(-EPROBE_DEFER);
+
        delay = of_get_property(np, "startup-delay-us", NULL);
        if (delay)
                config->startup_delay = be32_to_cpu(*delay);
@@ -93,41 +102,10 @@ of_get_fixed_voltage_config(struct device *dev)
        if (of_find_property(np, "gpio-open-drain", NULL))
                config->gpio_is_open_drain = true;
 
-       return config;
-}
-
-static int fixed_voltage_is_enabled(struct regulator_dev *dev)
-{
-       struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
-       return data->is_enabled;
-}
-
-static int fixed_voltage_enable(struct regulator_dev *dev)
-{
-       struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
-       gpio_set_value_cansleep(data->gpio, data->enable_high);
-       data->is_enabled = true;
-
-       return 0;
-}
-
-static int fixed_voltage_disable(struct regulator_dev *dev)
-{
-       struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
-       gpio_set_value_cansleep(data->gpio, !data->enable_high);
-       data->is_enabled = false;
-
-       return 0;
-}
+       if (of_find_property(np, "vin-supply", NULL))
+               config->input_supply = "vin";
 
-static int fixed_voltage_enable_time(struct regulator_dev *dev)
-{
-       struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
-       return data->startup_delay;
+       return config;
 }
 
 static int fixed_voltage_get_voltage(struct regulator_dev *dev)
@@ -151,15 +129,6 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev,
        return data->microvolts;
 }
 
-static struct regulator_ops fixed_voltage_gpio_ops = {
-       .is_enabled = fixed_voltage_is_enabled,
-       .enable = fixed_voltage_enable,
-       .disable = fixed_voltage_disable,
-       .enable_time = fixed_voltage_enable_time,
-       .get_voltage = fixed_voltage_get_voltage,
-       .list_voltage = fixed_voltage_list_voltage,
-};
-
 static struct regulator_ops fixed_voltage_ops = {
        .get_voltage = fixed_voltage_get_voltage,
        .list_voltage = fixed_voltage_list_voltage,
@@ -172,10 +141,13 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
        struct regulator_config cfg = { };
        int ret;
 
-       if (pdev->dev.of_node)
+       if (pdev->dev.of_node) {
                config = of_get_fixed_voltage_config(&pdev->dev);
-       else
+               if (IS_ERR(config))
+                       return PTR_ERR(config);
+       } else {
                config = pdev->dev.platform_data;
+       }
 
        if (!config)
                return -ENOMEM;
@@ -196,59 +168,44 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
        }
        drvdata->desc.type = REGULATOR_VOLTAGE;
        drvdata->desc.owner = THIS_MODULE;
+       drvdata->desc.ops = &fixed_voltage_ops;
 
-       if (config->microvolts)
-               drvdata->desc.n_voltages = 1;
+       drvdata->desc.enable_time = config->startup_delay;
 
-       drvdata->microvolts = config->microvolts;
-       drvdata->gpio = config->gpio;
-       drvdata->startup_delay = config->startup_delay;
-
-       if (gpio_is_valid(config->gpio)) {
-               int gpio_flag;
-               drvdata->enable_high = config->enable_high;
-
-               /* FIXME: Remove below print warning
-                *
-                * config->gpio must be set to -EINVAL by platform code if
-                * GPIO control is not required. However, early adopters
-                * not requiring GPIO control may forget to initialize
-                * config->gpio to -EINVAL. This will cause GPIO 0 to be used
-                * for GPIO control.
-                *
-                * This warning will be removed once there are a couple of users
-                * for this driver.
-                */
-               if (!config->gpio)
-                       dev_warn(&pdev->dev,
-                               "using GPIO 0 for regulator enable control\n");
-
-               /*
-                * set output direction without changing state
-                * to prevent glitch
-                */
-               drvdata->is_enabled = config->enabled_at_boot;
-               ret = drvdata->is_enabled ?
-                               config->enable_high : !config->enable_high;
-               gpio_flag = ret ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-
-               if (config->gpio_is_open_drain)
-                       gpio_flag |= GPIOF_OPEN_DRAIN;
-
-               ret = gpio_request_one(config->gpio, gpio_flag,
-                                               config->supply_name);
-               if (ret) {
+       if (config->input_supply) {
+               drvdata->desc.supply_name = kstrdup(config->input_supply,
+                                                       GFP_KERNEL);
+               if (!drvdata->desc.supply_name) {
                        dev_err(&pdev->dev,
-                          "Could not obtain regulator enable GPIO %d: %d\n",
-                                                       config->gpio, ret);
+                               "Failed to allocate input supply\n");
+                       ret = -ENOMEM;
                        goto err_name;
                }
+       }
+
+       if (config->microvolts)
+               drvdata->desc.n_voltages = 1;
 
-               drvdata->desc.ops = &fixed_voltage_gpio_ops;
+       drvdata->microvolts = config->microvolts;
 
+       if (config->gpio >= 0)
+               cfg.ena_gpio = config->gpio;
+       cfg.ena_gpio_invert = !config->enable_high;
+       if (config->enabled_at_boot) {
+               if (config->enable_high) {
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+               } else {
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+               }
        } else {
-               drvdata->desc.ops = &fixed_voltage_ops;
+               if (config->enable_high) {
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+               } else {
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+               }
        }
+       if (config->gpio_is_open_drain)
+               cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
 
        cfg.dev = &pdev->dev;
        cfg.init_data = config->init_data;
@@ -259,7 +216,7 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
        if (IS_ERR(drvdata->dev)) {
                ret = PTR_ERR(drvdata->dev);
                dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
-               goto err_gpio;
+               goto err_input;
        }
 
        platform_set_drvdata(pdev, drvdata);
@@ -269,9 +226,8 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
 
        return 0;
 
-err_gpio:
-       if (gpio_is_valid(config->gpio))
-               gpio_free(config->gpio);
+err_input:
+       kfree(drvdata->desc.supply_name);
 err_name:
        kfree(drvdata->desc.name);
 err:
@@ -283,8 +239,7 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)
        struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
 
        regulator_unregister(drvdata->dev);
-       if (gpio_is_valid(drvdata->gpio))
-               gpio_free(drvdata->gpio);
+       kfree(drvdata->desc.supply_name);
        kfree(drvdata->desc.name);
 
        return 0;
@@ -296,8 +251,6 @@ static const struct of_device_id fixed_of_match[] __devinitconst = {
        {},
 };
 MODULE_DEVICE_TABLE(of, fixed_of_match);
-#else
-#define fixed_of_match NULL
 #endif
 
 static struct platform_driver regulator_fixed_voltage_driver = {
@@ -306,7 +259,7 @@ static struct platform_driver regulator_fixed_voltage_driver = {
        .driver         = {
                .name           = "reg-fixed-voltage",
                .owner          = THIS_MODULE,
-               .of_match_table = fixed_of_match,
+               .of_match_table = of_match_ptr(fixed_of_match),
        },
 };
 
index 242851a4c1a606d69b41efad88f74dc1060817db..34b67bee9323ce00a49b30bb0cf7d9256660b6f8 100644 (file)
@@ -36,11 +36,6 @@ struct gpio_regulator_data {
        struct regulator_desc desc;
        struct regulator_dev *dev;
 
-       int enable_gpio;
-       bool enable_high;
-       bool is_enabled;
-       unsigned startup_delay;
-
        struct gpio *gpios;
        int nr_gpios;
 
@@ -50,44 +45,6 @@ struct gpio_regulator_data {
        int state;
 };
 
-static int gpio_regulator_is_enabled(struct regulator_dev *dev)
-{
-       struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
-       return data->is_enabled;
-}
-
-static int gpio_regulator_enable(struct regulator_dev *dev)
-{
-       struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
-       if (gpio_is_valid(data->enable_gpio)) {
-               gpio_set_value_cansleep(data->enable_gpio, data->enable_high);
-               data->is_enabled = true;
-       }
-
-       return 0;
-}
-
-static int gpio_regulator_disable(struct regulator_dev *dev)
-{
-       struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
-       if (gpio_is_valid(data->enable_gpio)) {
-               gpio_set_value_cansleep(data->enable_gpio, !data->enable_high);
-               data->is_enabled = false;
-       }
-
-       return 0;
-}
-
-static int gpio_regulator_enable_time(struct regulator_dev *dev)
-{
-       struct gpio_regulator_data *data = rdev_get_drvdata(dev);
-
-       return data->startup_delay;
-}
-
 static int gpio_regulator_get_value(struct regulator_dev *dev)
 {
        struct gpio_regulator_data *data = rdev_get_drvdata(dev);
@@ -153,20 +110,12 @@ static int gpio_regulator_set_current_limit(struct regulator_dev *dev,
 }
 
 static struct regulator_ops gpio_regulator_voltage_ops = {
-       .is_enabled = gpio_regulator_is_enabled,
-       .enable = gpio_regulator_enable,
-       .disable = gpio_regulator_disable,
-       .enable_time = gpio_regulator_enable_time,
        .get_voltage = gpio_regulator_get_value,
        .set_voltage = gpio_regulator_set_voltage,
        .list_voltage = gpio_regulator_list_voltage,
 };
 
 static struct regulator_ops gpio_regulator_current_ops = {
-       .is_enabled = gpio_regulator_is_enabled,
-       .enable = gpio_regulator_enable,
-       .disable = gpio_regulator_disable,
-       .enable_time = gpio_regulator_enable_time,
        .get_current_limit = gpio_regulator_get_value,
        .set_current_limit = gpio_regulator_set_current_limit,
 };
@@ -213,6 +162,7 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev)
        drvdata->nr_states = config->nr_states;
 
        drvdata->desc.owner = THIS_MODULE;
+       drvdata->desc.enable_time = config->startup_delay;
 
        /* handle regulator type*/
        switch (config->type) {
@@ -232,52 +182,12 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev)
                break;
        }
 
-       drvdata->enable_gpio = config->enable_gpio;
-       drvdata->startup_delay = config->startup_delay;
-
-       if (gpio_is_valid(config->enable_gpio)) {
-               drvdata->enable_high = config->enable_high;
-
-               ret = gpio_request(config->enable_gpio, config->supply_name);
-               if (ret) {
-                       dev_err(&pdev->dev,
-                          "Could not obtain regulator enable GPIO %d: %d\n",
-                                               config->enable_gpio, ret);
-                       goto err_memstate;
-               }
-
-               /* set output direction without changing state
-                * to prevent glitch
-                */
-               if (config->enabled_at_boot) {
-                       drvdata->is_enabled = true;
-                       ret = gpio_direction_output(config->enable_gpio,
-                                                   config->enable_high);
-               } else {
-                       drvdata->is_enabled = false;
-                       ret = gpio_direction_output(config->enable_gpio,
-                                                   !config->enable_high);
-               }
-
-               if (ret) {
-                       dev_err(&pdev->dev,
-                          "Could not configure regulator enable GPIO %d direction: %d\n",
-                                               config->enable_gpio, ret);
-                       goto err_enablegpio;
-               }
-       } else {
-               /* Regulator without GPIO control is considered
-                * always enabled
-                */
-               drvdata->is_enabled = true;
-       }
-
        drvdata->nr_gpios = config->nr_gpios;
        ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
        if (ret) {
                dev_err(&pdev->dev,
                   "Could not obtain regulator setting GPIOs: %d\n", ret);
-               goto err_enablegpio;
+               goto err_memstate;
        }
 
        /* build initial state from gpio init data. */
@@ -292,6 +202,21 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev)
        cfg.init_data = config->init_data;
        cfg.driver_data = drvdata;
 
+       if (config->enable_gpio >= 0)
+               cfg.ena_gpio = config->enable_gpio;
+       cfg.ena_gpio_invert = !config->enable_high;
+       if (config->enabled_at_boot) {
+               if (config->enable_high)
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+               else
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+       } else {
+               if (config->enable_high)
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_LOW;
+               else
+                       cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+       }
+
        drvdata->dev = regulator_register(&drvdata->desc, &cfg);
        if (IS_ERR(drvdata->dev)) {
                ret = PTR_ERR(drvdata->dev);
@@ -305,9 +230,6 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev)
 
 err_stategpio:
        gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
-err_enablegpio:
-       if (gpio_is_valid(config->enable_gpio))
-               gpio_free(config->enable_gpio);
 err_memstate:
        kfree(drvdata->states);
 err_memgpio:
@@ -329,9 +251,6 @@ static int __devexit gpio_regulator_remove(struct platform_device *pdev)
        kfree(drvdata->states);
        kfree(drvdata->gpios);
 
-       if (gpio_is_valid(drvdata->enable_gpio))
-               gpio_free(drvdata->enable_gpio);
-
        kfree(drvdata->desc.name);
 
        return 0;
index 56d273f2560372371d1b3de53e0141d82bd8cfa6..1d145a07ada940d0308e1197eb4a961a9e988b9a 100644 (file)
@@ -75,19 +75,12 @@ static struct regulator_ops isl_core_ops = {
 
 static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
 {
-       int id = rdev_get_id(dev);
-       return (id == 1) ? 1100000 : 1300000;
-}
-
-static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector)
-{
-       int id = rdev_get_id(dev);
-       return (id == 1) ? 1100000 : 1300000;
+       return dev->desc->min_uV;
 }
 
 static struct regulator_ops isl_fixed_ops = {
        .get_voltage    = isl6271a_get_fixed_voltage,
-       .list_voltage   = isl6271a_list_fixed_voltage,
+       .list_voltage   = regulator_list_voltage_linear,
 };
 
 static const struct regulator_desc isl_rd[] = {
@@ -107,6 +100,7 @@ static const struct regulator_desc isl_rd[] = {
                .ops            = &isl_fixed_ops,
                .type           = REGULATOR_VOLTAGE,
                .owner          = THIS_MODULE,
+               .min_uV         = 1100000,
        }, {
                .name           = "LDO2",
                .id             = 2,
@@ -114,6 +108,7 @@ static const struct regulator_desc isl_rd[] = {
                .ops            = &isl_fixed_ops,
                .type           = REGULATOR_VOLTAGE,
                .owner          = THIS_MODULE,
+               .min_uV         = 1300000,
        },
 };
 
index 981bea9cb9d7d9c55a2f6e821523c695f35bf83c..7c6e3b8ff484ad03ab60fd25d07f74d80395a65f 100644 (file)
@@ -65,11 +65,11 @@ static const int buck_base_addr[] = {
 #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
 #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
 
-static const int buck_voltage_map[] = {
-          0,  800,  850,  900,  950, 1000, 1050, 1100,
-       1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
-       1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
-       3000, 3300,
+static const unsigned int buck_voltage_map[] = {
+             0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
+       1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+       1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
+       3000000, 3300000,
 };
 
 #define BUCK_TARGET_VOL_MASK 0x3f
@@ -98,39 +98,19 @@ static const int buck_voltage_map[] = {
 #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
 #define LDO_VOL_CONTR_MASK 0x0f
 
-static const int ldo45_voltage_map[] = {
-       1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
-       1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+static const unsigned int ldo45_voltage_map[] = {
+       1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
+       1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
 };
 
-static const int ldo123_voltage_map[] = {
-       1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
-       2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+static const unsigned int ldo123_voltage_map[] = {
+       1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+       2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
 };
 
-static const int *ldo_voltage_map[] = {
-       ldo123_voltage_map, /* LDO1 */
-       ldo123_voltage_map, /* LDO2 */
-       ldo123_voltage_map, /* LDO3 */
-       ldo45_voltage_map, /* LDO4 */
-       ldo45_voltage_map, /* LDO5 */
-};
-
-#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP3971_LDO1)])
-
 #define LDO_VOL_MIN_IDX 0x00
 #define LDO_VOL_MAX_IDX 0x0f
 
-static int lp3971_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-       int ldo = rdev_get_id(dev) - LP3971_LDO1;
-
-       if (index > LDO_VOL_MAX_IDX)
-               return -EINVAL;
-
-       return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
-}
-
 static int lp3971_ldo_is_enabled(struct regulator_dev *dev)
 {
        struct lp3971 *lp3971 = rdev_get_drvdata(dev);
@@ -169,7 +149,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev)
        reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo));
        val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK;
 
-       return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
+       return dev->desc->volt_table[val];
 }
 
 static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -184,7 +164,7 @@ static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3971_ldo_ops = {
-       .list_voltage = lp3971_ldo_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .is_enabled = lp3971_ldo_is_enabled,
        .enable = lp3971_ldo_enable,
        .disable = lp3971_ldo_disable,
@@ -192,14 +172,6 @@ static struct regulator_ops lp3971_ldo_ops = {
        .set_voltage_sel = lp3971_ldo_set_voltage_sel,
 };
 
-static int lp3971_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-       if (index < BUCK_TARGET_VOL_MIN_IDX || index > BUCK_TARGET_VOL_MAX_IDX)
-               return -EINVAL;
-
-       return 1000 * buck_voltage_map[index];
-}
-
 static int lp3971_dcdc_is_enabled(struct regulator_dev *dev)
 {
        struct lp3971 *lp3971 = rdev_get_drvdata(dev);
@@ -240,7 +212,7 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev)
        reg &= BUCK_TARGET_VOL_MASK;
 
        if (reg <= BUCK_TARGET_VOL_MAX_IDX)
-               val = 1000 * buck_voltage_map[reg];
+               val = buck_voltage_map[reg];
        else {
                val = 0;
                dev_warn(&dev->dev, "chip reported incorrect voltage value.\n");
@@ -273,7 +245,7 @@ static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3971_dcdc_ops = {
-       .list_voltage = lp3971_dcdc_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .is_enabled = lp3971_dcdc_is_enabled,
        .enable = lp3971_dcdc_enable,
        .disable = lp3971_dcdc_disable,
@@ -287,6 +259,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_LDO1,
                .ops = &lp3971_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+               .volt_table = ldo123_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -295,6 +268,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_LDO2,
                .ops = &lp3971_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+               .volt_table = ldo123_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -303,6 +277,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_LDO3,
                .ops = &lp3971_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo123_voltage_map),
+               .volt_table = ldo123_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -311,6 +286,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_LDO4,
                .ops = &lp3971_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+               .volt_table = ldo45_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -319,6 +295,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_LDO5,
                .ops = &lp3971_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo45_voltage_map),
+               .volt_table = ldo45_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -327,6 +304,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_DCDC1,
                .ops = &lp3971_dcdc_ops,
                .n_voltages = ARRAY_SIZE(buck_voltage_map),
+               .volt_table = buck_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -335,6 +313,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_DCDC2,
                .ops = &lp3971_dcdc_ops,
                .n_voltages = ARRAY_SIZE(buck_voltage_map),
+               .volt_table = buck_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -343,6 +322,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3971_DCDC3,
                .ops = &lp3971_dcdc_ops,
                .n_voltages = ARRAY_SIZE(buck_voltage_map),
+               .volt_table = buck_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
index de073df7d3449a69d0a991c27c95f23f6b0285e3..3cdc755d9b225774aabf25a1101f4aeeae591cec 100644 (file)
@@ -74,54 +74,40 @@ struct lp3972 {
 #define LP3972_OVER2_LDO4_EN   BIT(4)
 #define LP3972_OVER1_S_EN      BIT(2)
 
-static const int ldo1_voltage_map[] = {
-       1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
-       1900, 1925, 1950, 1975, 2000,
+static const unsigned int ldo1_voltage_map[] = {
+       1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
+       1900000, 1925000, 1950000, 1975000, 2000000,
 };
 
-static const int ldo23_voltage_map[] = {
-       1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
-       2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
+static const unsigned int ldo23_voltage_map[] = {
+       1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+       2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
 };
 
-static const int ldo4_voltage_map[] = {
-       1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
-       1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
+static const unsigned int ldo4_voltage_map[] = {
+       1000000, 1050000, 1100000, 1150000, 1200000, 1250000, 1300000, 1350000,
+       1400000, 1500000, 1800000, 1900000, 2500000, 2800000, 3000000, 3300000,
 };
 
-static const int ldo5_voltage_map[] = {
-          0,    0,    0,    0,    0,  850,  875,  900,
-        925,  950,  975, 1000, 1025, 1050, 1075, 1100,
-       1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
-       1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int ldo5_voltage_map[] = {
+             0,       0,       0,       0,       0,  850000,  875000,  900000,
+        925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+       1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+       1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
 };
 
-static const int buck1_voltage_map[] = {
-        725,  750,  775,  800,  825,  850,  875,  900,
-        925,  950,  975, 1000, 1025, 1050, 1075, 1100,
-       1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
-       1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int buck1_voltage_map[] = {
+        725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
+        925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+       1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+       1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
 };
 
-static const int buck23_voltage_map[] = {
-          0,  800,  850,  900,  950, 1000, 1050, 1100,
-       1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
-       1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
-       3000, 3300,
-};
-
-static const int *ldo_voltage_map[] = {
-       ldo1_voltage_map,
-       ldo23_voltage_map,
-       ldo23_voltage_map,
-       ldo4_voltage_map,
-       ldo5_voltage_map,
-};
-
-static const int *buck_voltage_map[] = {
-       buck1_voltage_map,
-       buck23_voltage_map,
-       buck23_voltage_map,
+static const unsigned int buck23_voltage_map[] = {
+             0,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
+       1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+       1550000, 1600000, 1650000, 1700000, 1800000, 1900000, 2500000, 2800000,
+       3000000, 3300000,
 };
 
 static const int ldo_output_enable_mask[] = {
@@ -160,7 +146,6 @@ static const int buck_base_addr[] = {
        LP3972_B3TV_REG,
 };
 
-#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x])
 #define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
 #define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])
 
@@ -177,7 +162,6 @@ static const int buck_base_addr[] = {
 #define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00)
 #define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c)
 
-#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x])
 #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x])
 #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x])
 #define LP3972_BUCK_VOL_MASK 0x1f
@@ -242,17 +226,6 @@ static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val)
        return ret;
 }
 
-static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-       int ldo = rdev_get_id(dev) - LP3972_LDO1;
-
-       if (index < LP3972_LDO_VOL_MIN_IDX(ldo) ||
-           index > LP3972_LDO_VOL_MAX_IDX(ldo))
-               return -EINVAL;
-
-       return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index];
-}
-
 static int lp3972_ldo_is_enabled(struct regulator_dev *dev)
 {
        struct lp3972 *lp3972 = rdev_get_drvdata(dev);
@@ -294,7 +267,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev)
        reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo));
        val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask;
 
-       return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val];
+       return dev->desc->volt_table[val];
 }
 
 static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
@@ -337,7 +310,7 @@ static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3972_ldo_ops = {
-       .list_voltage = lp3972_ldo_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .is_enabled = lp3972_ldo_is_enabled,
        .enable = lp3972_ldo_enable,
        .disable = lp3972_ldo_disable,
@@ -345,17 +318,6 @@ static struct regulator_ops lp3972_ldo_ops = {
        .set_voltage_sel = lp3972_ldo_set_voltage_sel,
 };
 
-static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
-{
-       int buck = rdev_get_id(dev) - LP3972_DCDC1;
-
-       if (index < LP3972_BUCK_VOL_MIN_IDX(buck) ||
-           index > LP3972_BUCK_VOL_MAX_IDX(buck))
-               return -EINVAL;
-
-       return 1000 * buck_voltage_map[buck][index];
-}
-
 static int lp3972_dcdc_is_enabled(struct regulator_dev *dev)
 {
        struct lp3972 *lp3972 = rdev_get_drvdata(dev);
@@ -401,7 +363,7 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev)
        reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck));
        reg &= LP3972_BUCK_VOL_MASK;
        if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck))
-               val = 1000 * buck_voltage_map[buck][reg];
+               val = dev->desc->volt_table[reg];
        else {
                val = 0;
                dev_warn(&dev->dev, "chip reported incorrect voltage value."
@@ -436,7 +398,7 @@ static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
 }
 
 static struct regulator_ops lp3972_dcdc_ops = {
-       .list_voltage = lp3972_dcdc_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .is_enabled = lp3972_dcdc_is_enabled,
        .enable = lp3972_dcdc_enable,
        .disable = lp3972_dcdc_disable,
@@ -450,6 +412,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_LDO1,
                .ops = &lp3972_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo1_voltage_map),
+               .volt_table = ldo1_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -458,6 +421,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_LDO2,
                .ops = &lp3972_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+               .volt_table = ldo23_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -466,6 +430,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_LDO3,
                .ops = &lp3972_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo23_voltage_map),
+               .volt_table = ldo23_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -474,6 +439,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_LDO4,
                .ops = &lp3972_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo4_voltage_map),
+               .volt_table = ldo4_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -482,6 +448,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_LDO5,
                .ops = &lp3972_ldo_ops,
                .n_voltages = ARRAY_SIZE(ldo5_voltage_map),
+               .volt_table = ldo5_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -490,6 +457,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_DCDC1,
                .ops = &lp3972_dcdc_ops,
                .n_voltages = ARRAY_SIZE(buck1_voltage_map),
+               .volt_table = buck1_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -498,6 +466,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_DCDC2,
                .ops = &lp3972_dcdc_ops,
                .n_voltages = ARRAY_SIZE(buck23_voltage_map),
+               .volt_table = buck23_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
@@ -506,6 +475,7 @@ static const struct regulator_desc regulators[] = {
                .id = LP3972_DCDC3,
                .ops = &lp3972_dcdc_ops,
                .n_voltages = ARRAY_SIZE(buck23_voltage_map),
+               .volt_table = buck23_voltage_map,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
        },
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
new file mode 100644 (file)
index 0000000..212c38e
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@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/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/regulator/lp872x.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+
+/* Registers : LP8720/8725 shared */
+#define LP872X_GENERAL_CFG             0x00
+#define LP872X_LDO1_VOUT               0x01
+#define LP872X_LDO2_VOUT               0x02
+#define LP872X_LDO3_VOUT               0x03
+#define LP872X_LDO4_VOUT               0x04
+#define LP872X_LDO5_VOUT               0x05
+
+/* Registers : LP8720 */
+#define LP8720_BUCK_VOUT1              0x06
+#define LP8720_BUCK_VOUT2              0x07
+#define LP8720_ENABLE                  0x08
+
+/* Registers : LP8725 */
+#define LP8725_LILO1_VOUT              0x06
+#define LP8725_LILO2_VOUT              0x07
+#define LP8725_BUCK1_VOUT1             0x08
+#define LP8725_BUCK1_VOUT2             0x09
+#define LP8725_BUCK2_VOUT1             0x0A
+#define LP8725_BUCK2_VOUT2             0x0B
+#define LP8725_BUCK_CTRL               0x0C
+#define LP8725_LDO_CTRL                        0x0D
+
+/* Mask/shift : LP8720/LP8725 shared */
+#define LP872X_VOUT_M                  0x1F
+#define LP872X_START_DELAY_M           0xE0
+#define LP872X_START_DELAY_S           5
+#define LP872X_EN_LDO1_M               BIT(0)
+#define LP872X_EN_LDO2_M               BIT(1)
+#define LP872X_EN_LDO3_M               BIT(2)
+#define LP872X_EN_LDO4_M               BIT(3)
+#define LP872X_EN_LDO5_M               BIT(4)
+
+/* Mask/shift : LP8720 */
+#define LP8720_TIMESTEP_S              0               /* Addr 00h */
+#define LP8720_TIMESTEP_M              BIT(0)
+#define LP8720_EXT_DVS_M               BIT(2)
+#define LP8720_BUCK_FPWM_S             5               /* Addr 07h */
+#define LP8720_BUCK_FPWM_M             BIT(5)
+#define LP8720_EN_BUCK_M               BIT(5)          /* Addr 08h */
+#define LP8720_DVS_SEL_M               BIT(7)
+
+/* Mask/shift : LP8725 */
+#define LP8725_TIMESTEP_M              0xC0            /* Addr 00h */
+#define LP8725_TIMESTEP_S              6
+#define LP8725_BUCK1_EN_M              BIT(0)
+#define LP8725_DVS1_M                  BIT(2)
+#define LP8725_DVS2_M                  BIT(3)
+#define LP8725_BUCK2_EN_M              BIT(4)
+#define LP8725_BUCK_CL_M               0xC0            /* Addr 09h, 0Bh */
+#define LP8725_BUCK_CL_S               6
+#define LP8725_BUCK1_FPWM_S            1               /* Addr 0Ch */
+#define LP8725_BUCK1_FPWM_M            BIT(1)
+#define LP8725_BUCK2_FPWM_S            5
+#define LP8725_BUCK2_FPWM_M            BIT(5)
+#define LP8725_EN_LILO1_M              BIT(5)          /* Addr 0Dh */
+#define LP8725_EN_LILO2_M              BIT(6)
+
+/* PWM mode */
+#define LP872X_FORCE_PWM               1
+#define LP872X_AUTO_PWM                        0
+
+#define LP8720_NUM_REGULATORS          6
+#define LP8725_NUM_REGULATORS          9
+#define EXTERN_DVS_USED                        0
+#define MAX_DELAY                      6
+
+/* dump registers in regmap-debugfs */
+#define MAX_REGISTERS                  0x0F
+
+enum lp872x_id {
+       LP8720,
+       LP8725,
+};
+
+struct lp872x {
+       struct regmap *regmap;
+       struct device *dev;
+       enum lp872x_id chipid;
+       struct lp872x_platform_data *pdata;
+       struct regulator_dev **regulators;
+       int num_regulators;
+       enum lp872x_dvs_state dvs_pin;
+       int dvs_gpio;
+};
+
+/* LP8720/LP8725 shared voltage table for LDOs */
+static const unsigned int lp872x_ldo_vtbl[] = {
+       1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
+       1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 2000000,
+       2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2650000, 2700000,
+       2750000, 2800000, 2850000, 2900000, 2950000, 3000000, 3100000, 3300000,
+};
+
+/* LP8720 LDO4 voltage table */
+static const unsigned int lp8720_ldo4_vtbl[] = {
+        800000,  850000,  900000, 1000000, 1100000, 1200000, 1250000, 1300000,
+       1350000, 1400000, 1450000, 1500000, 1550000, 1600000, 1650000, 1700000,
+       1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000,
+       2400000, 2500000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000,
+};
+
+/* LP8725 LILO(Low Input Low Output) voltage table */
+static const unsigned int lp8725_lilo_vtbl[] = {
+        800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+       1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000,
+       1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+       2600000, 2700000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
+};
+
+/* LP8720 BUCK voltage table */
+#define EXT_R          0       /* external resistor divider */
+static const unsigned int lp8720_buck_vtbl[] = {
+         EXT_R,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
+       1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+       1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
+       1950000, 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000,
+};
+
+/* LP8725 BUCK voltage table */
+static const unsigned int lp8725_buck_vtbl[] = {
+        800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
+       1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1700000,
+       1750000, 1800000, 1850000, 1900000, 2000000, 2100000, 2200000, 2300000,
+       2400000, 2500000, 2600000, 2700000, 2800000, 2850000, 2900000, 3000000,
+};
+
+/* LP8725 BUCK current limit */
+static const unsigned int lp8725_buck_uA[] = {
+       460000, 780000, 1050000, 1370000,
+};
+
+static int lp872x_read_byte(struct lp872x *lp, u8 addr, u8 *data)
+{
+       int ret;
+       unsigned int val;
+
+       ret = regmap_read(lp->regmap, addr, &val);
+       if (ret < 0) {
+               dev_err(lp->dev, "failed to read 0x%.2x\n", addr);
+               return ret;
+       }
+
+       *data = (u8)val;
+       return 0;
+}
+
+static inline int lp872x_write_byte(struct lp872x *lp, u8 addr, u8 data)
+{
+       return regmap_write(lp->regmap, addr, data);
+}
+
+static inline int lp872x_update_bits(struct lp872x *lp, u8 addr,
+                               unsigned int mask, u8 data)
+{
+       return regmap_update_bits(lp->regmap, addr, mask, data);
+}
+
+static int _rdev_to_offset(struct regulator_dev *rdev)
+{
+       enum lp872x_regulator_id id = rdev_get_id(rdev);
+
+       switch (id) {
+       case LP8720_ID_LDO1 ... LP8720_ID_BUCK:
+               return id;
+       case LP8725_ID_LDO1 ... LP8725_ID_BUCK2:
+               return id - LP8725_ID_BASE;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int lp872x_get_timestep_usec(struct lp872x *lp)
+{
+       enum lp872x_id chip = lp->chipid;
+       u8 val, mask, shift;
+       int *time_usec, size, ret;
+       int lp8720_time_usec[] = { 25, 50 };
+       int lp8725_time_usec[] = { 32, 64, 128, 256 };
+
+       switch (chip) {
+       case LP8720:
+               mask = LP8720_TIMESTEP_M;
+               shift = LP8720_TIMESTEP_S;
+               time_usec = &lp8720_time_usec[0];
+               size = ARRAY_SIZE(lp8720_time_usec);
+               break;
+       case LP8725:
+               mask = LP8725_TIMESTEP_M;
+               shift = LP8725_TIMESTEP_S;
+               time_usec = &lp8725_time_usec[0];
+               size = ARRAY_SIZE(lp8725_time_usec);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
+       if (ret)
+               return -EINVAL;
+
+       val = (val & mask) >> shift;
+       if (val >= size)
+               return -EINVAL;
+
+       return *(time_usec + val);
+}
+
+static int lp872x_regulator_enable_time(struct regulator_dev *rdev)
+{
+       struct lp872x *lp = rdev_get_drvdata(rdev);
+       enum lp872x_regulator_id regulator = rdev_get_id(rdev);
+       int time_step_us = lp872x_get_timestep_usec(lp);
+       int ret, offset;
+       u8 addr, val;
+
+       if (time_step_us < 0)
+               return -EINVAL;
+
+       switch (regulator) {
+       case LP8720_ID_LDO1 ... LP8720_ID_LDO5:
+       case LP8725_ID_LDO1 ... LP8725_ID_LILO2:
+               offset = _rdev_to_offset(rdev);
+               if (offset < 0)
+                       return -EINVAL;
+
+               addr = LP872X_LDO1_VOUT + offset;
+               break;
+       case LP8720_ID_BUCK:
+               addr = LP8720_BUCK_VOUT1;
+               break;
+       case LP8725_ID_BUCK1:
+               addr = LP8725_BUCK1_VOUT1;
+               break;
+       case LP8725_ID_BUCK2:
+               addr = LP8725_BUCK2_VOUT1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = lp872x_read_byte(lp, addr, &val);
+       if (ret)
+               return ret;
+
+       val = (val & LP872X_START_DELAY_M) >> LP872X_START_DELAY_S;
+
+       return val > MAX_DELAY ? 0 : val * time_step_us;
+}
+
+static void lp872x_set_dvs(struct lp872x *lp, int gpio)
+{
+       enum lp872x_dvs_sel dvs_sel = lp->pdata->dvs->vsel;
+       enum lp872x_dvs_state state;
+
+       state = dvs_sel == SEL_V1 ? DVS_HIGH : DVS_LOW;
+       gpio_set_value(gpio, state);
+       lp->dvs_pin = state;
+}
+
+static u8 lp872x_select_buck_vout_addr(struct lp872x *lp,
+                               enum lp872x_regulator_id buck)
+{
+       u8 val, addr;
+
+       if (lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val))
+               return 0;
+
+       switch (buck) {
+       case LP8720_ID_BUCK:
+               if (val & LP8720_EXT_DVS_M) {
+                       addr = (lp->dvs_pin == DVS_HIGH) ?
+                               LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2;
+               } else {
+                       if (lp872x_read_byte(lp, LP8720_ENABLE, &val))
+                               return 0;
+
+                       addr = val & LP8720_DVS_SEL_M ?
+                               LP8720_BUCK_VOUT1 : LP8720_BUCK_VOUT2;
+               }
+               break;
+       case LP8725_ID_BUCK1:
+               if (val & LP8725_DVS1_M)
+                       addr = LP8725_BUCK1_VOUT1;
+               else
+                       addr = (lp->dvs_pin == DVS_HIGH) ?
+                               LP8725_BUCK1_VOUT1 : LP8725_BUCK1_VOUT2;
+               break;
+       case LP8725_ID_BUCK2:
+               addr =  val & LP8725_DVS2_M ?
+                       LP8725_BUCK2_VOUT1 : LP8725_BUCK2_VOUT2;
+               break;
+       default:
+               return 0;
+       }
+
+       return addr;
+}
+
+static bool lp872x_is_valid_buck_addr(u8 addr)
+{
+       switch (addr) {
+       case LP8720_BUCK_VOUT1:
+       case LP8720_BUCK_VOUT2:
+       case LP8725_BUCK1_VOUT1:
+       case LP8725_BUCK1_VOUT2:
+       case LP8725_BUCK2_VOUT1:
+       case LP8725_BUCK2_VOUT2:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int lp872x_buck_set_voltage_sel(struct regulator_dev *rdev,
+                                       unsigned selector)
+{
+       struct lp872x *lp = rdev_get_drvdata(rdev);
+       enum lp872x_regulator_id buck = rdev_get_id(rdev);
+       u8 addr, mask = LP872X_VOUT_M;
+       struct lp872x_dvs *dvs = lp->pdata->dvs;
+
+       if (dvs && gpio_is_valid(dvs->gpio))
+               lp872x_set_dvs(lp, dvs->gpio);
+
+       addr = lp872x_select_buck_vout_addr(lp, buck);
+       if (!lp872x_is_valid_buck_addr(addr))
+               return -EINVAL;
+
+       return lp872x_update_bits(lp, addr, mask, selector);
+}
+
+static int lp872x_buck_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct lp872x *lp = rdev_get_drvdata(rdev);
+       enum lp872x_regulator_id buck = rdev_get_id(rdev);
+       u8 addr, val;
+       int ret;
+
+       addr = lp872x_select_buck_vout_addr(lp, buck);
+       if (!lp872x_is_valid_buck_addr(addr))
+               return -EINVAL;
+
+       ret = lp872x_read_byte(lp, addr, &val);
+       if (ret)
+               return ret;
+
+       return val & LP872X_VOUT_M;
+}
+
+static int lp8725_buck_set_current_limit(struct regulator_dev *rdev,
+                                       int min_uA, int max_uA)
+{
+       struct lp872x *lp = rdev_get_drvdata(rdev);
+       enum lp872x_regulator_id buck = rdev_get_id(rdev);
+       int i, max = ARRAY_SIZE(lp8725_buck_uA);
+       u8 addr, val;
+
+       switch (buck) {
+       case LP8725_ID_BUCK1:
+               addr = LP8725_BUCK1_VOUT2;
+               break;
+       case LP8725_ID_BUCK2:
+               addr = LP8725_BUCK2_VOUT2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0 ; i < max ; i++)
+               if (lp8725_buck_uA[i] >= min_uA &&
+                       lp8725_buck_uA[i] <= max_uA)
+                       break;
+
+       if (i == max)
+               return -EINVAL;
+
+       val = i << LP8725_BUCK_CL_S;
+
+       return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val);
+}
+
+static int lp8725_buck_get_current_limit(struct regulator_dev *rdev)
+{
+       struct lp872x *lp = rdev_get_drvdata(rdev);
+       enum lp872x_regulator_id buck = rdev_get_id(rdev);
+       u8 addr, val;
+       int ret;
+
+       switch (buck) {
+       case LP8725_ID_BUCK1:
+               addr = LP8725_BUCK1_VOUT2;
+               break;
+       case LP8725_ID_BUCK2:
+               addr = LP8725_BUCK2_VOUT2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = lp872x_read_byte(lp, addr, &val);
+       if (ret)
+               return ret;
+
+       val = (val & LP8725_BUCK_CL_M) >> LP8725_BUCK_CL_S;
+
+       return (val < ARRAY_SIZE(lp8725_buck_uA)) ?
+                       lp8725_buck_uA[val] : -EINVAL;
+}
+
+static int lp872x_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct lp872x *lp = rdev_get_drvdata(rdev);
+       enum lp872x_regulator_id buck = rdev_get_id(rdev);
+       u8 addr, mask, shift, val;
+
+       switch (buck) {
+       case LP8720_ID_BUCK:
+               addr = LP8720_BUCK_VOUT2;
+               mask = LP8720_BUCK_FPWM_M;
+               shift = LP8720_BUCK_FPWM_S;
+               break;
+       case LP8725_ID_BUCK1:
+               addr = LP8725_BUCK_CTRL;
+               mask = LP8725_BUCK1_FPWM_M;
+               shift = LP8725_BUCK1_FPWM_S;
+               break;
+       case LP8725_ID_BUCK2:
+               addr = LP8725_BUCK_CTRL;
+               mask = LP8725_BUCK2_FPWM_M;
+               shift = LP8725_BUCK2_FPWM_S;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (mode == REGULATOR_MODE_FAST)
+               val = LP872X_FORCE_PWM << shift;
+       else if (mode == REGULATOR_MODE_NORMAL)
+               val = LP872X_AUTO_PWM << shift;
+       else
+               return -EINVAL;
+
+       return lp872x_update_bits(lp, addr, mask, val);
+}
+
+static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev)
+{
+       struct lp872x *lp = rdev_get_drvdata(rdev);
+       enum lp872x_regulator_id buck = rdev_get_id(rdev);
+       u8 addr, mask, val;
+       int ret;
+
+       switch (buck) {
+       case LP8720_ID_BUCK:
+               addr = LP8720_BUCK_VOUT2;
+               mask = LP8720_BUCK_FPWM_M;
+               break;
+       case LP8725_ID_BUCK1:
+               addr = LP8725_BUCK_CTRL;
+               mask = LP8725_BUCK1_FPWM_M;
+               break;
+       case LP8725_ID_BUCK2:
+               addr = LP8725_BUCK_CTRL;
+               mask = LP8725_BUCK2_FPWM_M;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = lp872x_read_byte(lp, addr, &val);
+       if (ret)
+               return ret;
+
+       return val & mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops lp872x_ldo_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable_time = lp872x_regulator_enable_time,
+};
+
+static struct regulator_ops lp8720_buck_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = lp872x_buck_set_voltage_sel,
+       .get_voltage_sel = lp872x_buck_get_voltage_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable_time = lp872x_regulator_enable_time,
+       .set_mode = lp872x_buck_set_mode,
+       .get_mode = lp872x_buck_get_mode,
+};
+
+static struct regulator_ops lp8725_buck_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = lp872x_buck_set_voltage_sel,
+       .get_voltage_sel = lp872x_buck_get_voltage_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable_time = lp872x_regulator_enable_time,
+       .set_mode = lp872x_buck_set_mode,
+       .get_mode = lp872x_buck_get_mode,
+       .set_current_limit = lp8725_buck_set_current_limit,
+       .get_current_limit = lp8725_buck_get_current_limit,
+};
+
+static struct regulator_desc lp8720_regulator_desc[] = {
+       {
+               .name = "ldo1",
+               .id = LP8720_ID_LDO1,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO1_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8720_ENABLE,
+               .enable_mask = LP872X_EN_LDO1_M,
+       },
+       {
+               .name = "ldo2",
+               .id = LP8720_ID_LDO2,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO2_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8720_ENABLE,
+               .enable_mask = LP872X_EN_LDO2_M,
+       },
+       {
+               .name = "ldo3",
+               .id = LP8720_ID_LDO3,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO3_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8720_ENABLE,
+               .enable_mask = LP872X_EN_LDO3_M,
+       },
+       {
+               .name = "ldo4",
+               .id = LP8720_ID_LDO4,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp8720_ldo4_vtbl),
+               .volt_table = lp8720_ldo4_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO4_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8720_ENABLE,
+               .enable_mask = LP872X_EN_LDO4_M,
+       },
+       {
+               .name = "ldo5",
+               .id = LP8720_ID_LDO5,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO5_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8720_ENABLE,
+               .enable_mask = LP872X_EN_LDO5_M,
+       },
+       {
+               .name = "buck",
+               .id = LP8720_ID_BUCK,
+               .ops = &lp8720_buck_ops,
+               .n_voltages = ARRAY_SIZE(lp8720_buck_vtbl),
+               .volt_table = lp8720_buck_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8720_ENABLE,
+               .enable_mask = LP8720_EN_BUCK_M,
+       },
+};
+
+static struct regulator_desc lp8725_regulator_desc[] = {
+       {
+               .name = "ldo1",
+               .id = LP8725_ID_LDO1,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO1_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8725_LDO_CTRL,
+               .enable_mask = LP872X_EN_LDO1_M,
+       },
+       {
+               .name = "ldo2",
+               .id = LP8725_ID_LDO2,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO2_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8725_LDO_CTRL,
+               .enable_mask = LP872X_EN_LDO2_M,
+       },
+       {
+               .name = "ldo3",
+               .id = LP8725_ID_LDO3,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO3_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8725_LDO_CTRL,
+               .enable_mask = LP872X_EN_LDO3_M,
+       },
+       {
+               .name = "ldo4",
+               .id = LP8725_ID_LDO4,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO4_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8725_LDO_CTRL,
+               .enable_mask = LP872X_EN_LDO4_M,
+       },
+       {
+               .name = "ldo5",
+               .id = LP8725_ID_LDO5,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp872x_ldo_vtbl),
+               .volt_table = lp872x_ldo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP872X_LDO5_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8725_LDO_CTRL,
+               .enable_mask = LP872X_EN_LDO5_M,
+       },
+       {
+               .name = "lilo1",
+               .id = LP8725_ID_LILO1,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
+               .volt_table = lp8725_lilo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8725_LILO1_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8725_LDO_CTRL,
+               .enable_mask = LP8725_EN_LILO1_M,
+       },
+       {
+               .name = "lilo2",
+               .id = LP8725_ID_LILO2,
+               .ops = &lp872x_ldo_ops,
+               .n_voltages = ARRAY_SIZE(lp8725_lilo_vtbl),
+               .volt_table = lp8725_lilo_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8725_LILO2_VOUT,
+               .vsel_mask = LP872X_VOUT_M,
+               .enable_reg = LP8725_LDO_CTRL,
+               .enable_mask = LP8725_EN_LILO2_M,
+       },
+       {
+               .name = "buck1",
+               .id = LP8725_ID_BUCK1,
+               .ops = &lp8725_buck_ops,
+               .n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
+               .volt_table = lp8725_buck_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP872X_GENERAL_CFG,
+               .enable_mask = LP8725_BUCK1_EN_M,
+       },
+       {
+               .name = "buck2",
+               .id = LP8725_ID_BUCK2,
+               .ops = &lp8725_buck_ops,
+               .n_voltages = ARRAY_SIZE(lp8725_buck_vtbl),
+               .volt_table = lp8725_buck_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP872X_GENERAL_CFG,
+               .enable_mask = LP8725_BUCK2_EN_M,
+       },
+};
+
+static int lp872x_check_dvs_validity(struct lp872x *lp)
+{
+       struct lp872x_dvs *dvs = lp->pdata->dvs;
+       u8 val = 0;
+       int ret;
+
+       ret = lp872x_read_byte(lp, LP872X_GENERAL_CFG, &val);
+       if (ret)
+               return ret;
+
+       ret = 0;
+       if (lp->chipid == LP8720) {
+               if (val & LP8720_EXT_DVS_M)
+                       ret = dvs ? 0 : -EINVAL;
+       } else {
+               if ((val & LP8725_DVS1_M) == EXTERN_DVS_USED)
+                       ret = dvs ? 0 : -EINVAL;
+       }
+
+       return ret;
+}
+
+static int lp872x_init_dvs(struct lp872x *lp)
+{
+       int ret, gpio;
+       struct lp872x_dvs *dvs = lp->pdata->dvs;
+       enum lp872x_dvs_state pinstate;
+
+       ret = lp872x_check_dvs_validity(lp);
+       if (ret) {
+               dev_warn(lp->dev, "invalid dvs data: %d\n", ret);
+               return ret;
+       }
+
+       gpio = dvs->gpio;
+       if (!gpio_is_valid(gpio)) {
+               dev_err(lp->dev, "invalid gpio: %d\n", gpio);
+               return -EINVAL;
+       }
+
+       pinstate = dvs->init_state;
+       ret = devm_gpio_request_one(lp->dev, gpio, pinstate, "LP872X DVS");
+       if (ret) {
+               dev_err(lp->dev, "gpio request err: %d\n", ret);
+               return ret;
+       }
+
+       lp->dvs_pin = pinstate;
+       lp->dvs_gpio = gpio;
+
+       return 0;
+}
+
+static int lp872x_config(struct lp872x *lp)
+{
+       struct lp872x_platform_data *pdata = lp->pdata;
+       int ret;
+
+       if (!pdata->update_config)
+               return 0;
+
+       ret = lp872x_write_byte(lp, LP872X_GENERAL_CFG, pdata->general_config);
+       if (ret)
+               return ret;
+
+       return lp872x_init_dvs(lp);
+}
+
+static struct regulator_init_data
+*lp872x_find_regulator_init_data(int id, struct lp872x *lp)
+{
+       int i;
+
+       for (i = 0; i < lp->num_regulators; i++) {
+               if (lp->pdata->regulator_data[i].id == id)
+                       return lp->pdata->regulator_data[i].init_data;
+       }
+
+       return NULL;
+}
+
+static int lp872x_regulator_register(struct lp872x *lp)
+{
+       struct regulator_desc *desc;
+       struct regulator_config cfg = { };
+       struct regulator_dev *rdev;
+       int i, ret;
+
+       for (i = 0 ; i < lp->num_regulators ; i++) {
+               desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] :
+                                               &lp8725_regulator_desc[i];
+
+               cfg.dev = lp->dev;
+               cfg.init_data = lp872x_find_regulator_init_data(desc->id, lp);
+               cfg.driver_data = lp;
+               cfg.regmap = lp->regmap;
+
+               rdev = regulator_register(desc, &cfg);
+               if (IS_ERR(rdev)) {
+                       dev_err(lp->dev, "regulator register err");
+                       ret =  PTR_ERR(rdev);
+                       goto err;
+               }
+
+               *(lp->regulators + i) = rdev;
+       }
+
+       return 0;
+err:
+       while (--i >= 0) {
+               rdev = *(lp->regulators + i);
+               regulator_unregister(rdev);
+       }
+       return ret;
+}
+
+static void lp872x_regulator_unregister(struct lp872x *lp)
+{
+       struct regulator_dev *rdev;
+       int i;
+
+       for (i = 0 ; i < lp->num_regulators ; i++) {
+               rdev = *(lp->regulators + i);
+               regulator_unregister(rdev);
+       }
+}
+
+static const struct regmap_config lp872x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = MAX_REGISTERS,
+};
+
+static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
+{
+       struct lp872x *lp;
+       struct lp872x_platform_data *pdata = cl->dev.platform_data;
+       int ret, size, num_regulators;
+       const int lp872x_num_regulators[] = {
+               [LP8720] = LP8720_NUM_REGULATORS,
+               [LP8725] = LP8725_NUM_REGULATORS,
+       };
+
+       if (!pdata) {
+               dev_err(&cl->dev, "no platform data\n");
+               return -EINVAL;
+       }
+
+       lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL);
+       if (!lp)
+               goto err_mem;
+
+       num_regulators = lp872x_num_regulators[id->driver_data];
+       size = sizeof(struct regulator_dev *) * num_regulators;
+
+       lp->regulators = devm_kzalloc(&cl->dev, size, GFP_KERNEL);
+       if (!lp->regulators)
+               goto err_mem;
+
+       lp->regmap = devm_regmap_init_i2c(cl, &lp872x_regmap_config);
+       if (IS_ERR(lp->regmap)) {
+               ret = PTR_ERR(lp->regmap);
+               dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
+               goto err_dev;
+       }
+
+       lp->dev = &cl->dev;
+       lp->pdata = pdata;
+       lp->chipid = id->driver_data;
+       lp->num_regulators = num_regulators;
+       i2c_set_clientdata(cl, lp);
+
+       ret = lp872x_config(lp);
+       if (ret)
+               goto err_dev;
+
+       return lp872x_regulator_register(lp);
+
+err_mem:
+       return -ENOMEM;
+err_dev:
+       return ret;
+}
+
+static int __devexit lp872x_remove(struct i2c_client *cl)
+{
+       struct lp872x *lp = i2c_get_clientdata(cl);
+
+       lp872x_regulator_unregister(lp);
+       return 0;
+}
+
+static const struct i2c_device_id lp872x_ids[] = {
+       {"lp8720", LP8720},
+       {"lp8725", LP8725},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp872x_ids);
+
+static struct i2c_driver lp872x_driver = {
+       .driver = {
+               .name = "lp872x",
+               .owner = THIS_MODULE,
+       },
+       .probe = lp872x_probe,
+       .remove = __devexit_p(lp872x_remove),
+       .id_table = lp872x_ids,
+};
+
+module_i2c_driver(lp872x_driver);
+
+MODULE_DESCRIPTION("TI/National Semiconductor LP872x PMU Regulator Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c
new file mode 100644 (file)
index 0000000..6356e82
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * TI LP8788 MFD - buck regulator driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@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/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/lp8788.h>
+#include <linux/gpio.h>
+
+/* register address */
+#define LP8788_EN_BUCK                 0x0C
+#define LP8788_BUCK_DVS_SEL            0x1D
+#define LP8788_BUCK1_VOUT0             0x1E
+#define LP8788_BUCK1_VOUT1             0x1F
+#define LP8788_BUCK1_VOUT2             0x20
+#define LP8788_BUCK1_VOUT3             0x21
+#define LP8788_BUCK2_VOUT0             0x22
+#define LP8788_BUCK2_VOUT1             0x23
+#define LP8788_BUCK2_VOUT2             0x24
+#define LP8788_BUCK2_VOUT3             0x25
+#define LP8788_BUCK3_VOUT              0x26
+#define LP8788_BUCK4_VOUT              0x27
+#define LP8788_BUCK1_TIMESTEP          0x28
+#define LP8788_BUCK_PWM                        0x2D
+
+/* mask/shift bits */
+#define LP8788_EN_BUCK1_M              BIT(0)  /* Addr 0Ch */
+#define LP8788_EN_BUCK2_M              BIT(1)
+#define LP8788_EN_BUCK3_M              BIT(2)
+#define LP8788_EN_BUCK4_M              BIT(3)
+#define LP8788_BUCK1_DVS_SEL_M         0x04    /* Addr 1Dh */
+#define LP8788_BUCK1_DVS_M             0x03
+#define LP8788_BUCK1_DVS_S             0
+#define LP8788_BUCK2_DVS_SEL_M         0x40
+#define LP8788_BUCK2_DVS_M             0x30
+#define LP8788_BUCK2_DVS_S             4
+#define LP8788_BUCK1_DVS_I2C           BIT(2)
+#define LP8788_BUCK2_DVS_I2C           BIT(6)
+#define LP8788_BUCK1_DVS_PIN           (0 << 2)
+#define LP8788_BUCK2_DVS_PIN           (0 << 6)
+#define LP8788_VOUT_M                  0x1F    /* Addr 1Eh ~ 27h */
+#define LP8788_STARTUP_TIME_M          0xF8    /* Addr 28h ~ 2Bh */
+#define LP8788_STARTUP_TIME_S          3
+#define LP8788_FPWM_BUCK1_M            BIT(0)  /* Addr 2Dh */
+#define LP8788_FPWM_BUCK1_S            0
+#define LP8788_FPWM_BUCK2_M            BIT(1)
+#define LP8788_FPWM_BUCK2_S            1
+#define LP8788_FPWM_BUCK3_M            BIT(2)
+#define LP8788_FPWM_BUCK3_S            2
+#define LP8788_FPWM_BUCK4_M            BIT(3)
+#define LP8788_FPWM_BUCK4_S            3
+
+#define INVALID_ADDR                   0xFF
+#define LP8788_FORCE_PWM               1
+#define LP8788_AUTO_PWM                        0
+#define PIN_LOW                                0
+#define PIN_HIGH                       1
+#define ENABLE_TIME_USEC               32
+
+enum lp8788_dvs_state {
+       DVS_LOW  = GPIOF_OUT_INIT_LOW,
+       DVS_HIGH = GPIOF_OUT_INIT_HIGH,
+};
+
+enum lp8788_dvs_mode {
+       REGISTER,
+       EXTPIN,
+};
+
+enum lp8788_buck_id {
+       BUCK1,
+       BUCK2,
+       BUCK3,
+       BUCK4,
+};
+
+struct lp8788_pwm_map {
+       u8 mask;
+       u8 shift;
+};
+
+struct lp8788_buck {
+       struct lp8788 *lp;
+       struct regulator_dev *regulator;
+       struct lp8788_pwm_map *pmap;
+       void *dvs;
+};
+
+/* BUCK 1 ~ 4 voltage table */
+static const int lp8788_buck_vtbl[] = {
+        500000,  800000,  850000,  900000,  950000, 1000000, 1050000, 1100000,
+       1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+       1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
+       1950000, 2000000,
+};
+
+/* buck pwm mode selection : used for set/get_mode in regulator ops
+ * @forced pwm : fast mode
+ * @auto pwm   : normal mode
+ */
+static struct lp8788_pwm_map buck_pmap[] = {
+       [BUCK1] = {
+               .mask = LP8788_FPWM_BUCK1_M,
+               .shift = LP8788_FPWM_BUCK1_S,
+       },
+       [BUCK2] = {
+               .mask = LP8788_FPWM_BUCK2_M,
+               .shift = LP8788_FPWM_BUCK2_S,
+       },
+       [BUCK3] = {
+               .mask = LP8788_FPWM_BUCK3_M,
+               .shift = LP8788_FPWM_BUCK3_S,
+       },
+       [BUCK4] = {
+               .mask = LP8788_FPWM_BUCK4_M,
+               .shift = LP8788_FPWM_BUCK4_S,
+       },
+};
+
+static const u8 buck1_vout_addr[] = {
+       LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
+       LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
+};
+
+static const u8 buck2_vout_addr[] = {
+       LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1,
+       LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3,
+};
+
+static void lp8788_buck1_set_dvs(struct lp8788_buck *buck)
+{
+       struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs;
+       enum lp8788_dvs_state pinstate;
+
+       if (!dvs)
+               return;
+
+       pinstate = dvs->vsel == DVS_SEL_V0 ? DVS_LOW : DVS_HIGH;
+       if (gpio_is_valid(dvs->gpio))
+               gpio_set_value(dvs->gpio, pinstate);
+}
+
+static void lp8788_buck2_set_dvs(struct lp8788_buck *buck)
+{
+       struct lp8788_buck2_dvs *dvs = (struct lp8788_buck2_dvs *)buck->dvs;
+       enum lp8788_dvs_state pin1, pin2;
+
+       if (!dvs)
+               return;
+
+       switch (dvs->vsel) {
+       case DVS_SEL_V0:
+               pin1 = DVS_LOW;
+               pin2 = DVS_LOW;
+               break;
+       case DVS_SEL_V1:
+               pin1 = DVS_HIGH;
+               pin2 = DVS_LOW;
+               break;
+       case DVS_SEL_V2:
+               pin1 = DVS_LOW;
+               pin2 = DVS_HIGH;
+               break;
+       case DVS_SEL_V3:
+               pin1 = DVS_HIGH;
+               pin2 = DVS_HIGH;
+               break;
+       default:
+               return;
+       }
+
+       if (gpio_is_valid(dvs->gpio[0]))
+               gpio_set_value(dvs->gpio[0], pin1);
+
+       if (gpio_is_valid(dvs->gpio[1]))
+               gpio_set_value(dvs->gpio[1], pin2);
+}
+
+static void lp8788_set_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
+{
+       switch (id) {
+       case BUCK1:
+               lp8788_buck1_set_dvs(buck);
+               break;
+       case BUCK2:
+               lp8788_buck2_set_dvs(buck);
+               break;
+       default:
+               break;
+       }
+}
+
+static enum lp8788_dvs_mode
+lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck *buck, enum lp8788_buck_id id)
+{
+       u8 val, mask;
+
+       switch (id) {
+       case BUCK1:
+               mask = LP8788_BUCK1_DVS_SEL_M;
+               break;
+       case BUCK2:
+               mask = LP8788_BUCK2_DVS_SEL_M;
+               break;
+       default:
+               return REGISTER;
+       }
+
+       lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
+
+       return val & mask ? REGISTER : EXTPIN;
+}
+
+static bool lp8788_is_valid_buck_addr(u8 addr)
+{
+       switch (addr) {
+       case LP8788_BUCK1_VOUT0:
+       case LP8788_BUCK1_VOUT1:
+       case LP8788_BUCK1_VOUT2:
+       case LP8788_BUCK1_VOUT3:
+       case LP8788_BUCK2_VOUT0:
+       case LP8788_BUCK2_VOUT1:
+       case LP8788_BUCK2_VOUT2:
+       case LP8788_BUCK2_VOUT3:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck,
+                                       enum lp8788_buck_id id)
+{
+       enum lp8788_dvs_mode mode = lp8788_get_buck_dvs_ctrl_mode(buck, id);
+       struct lp8788_buck1_dvs *b1_dvs;
+       struct lp8788_buck2_dvs *b2_dvs;
+       u8 val, idx, addr;
+       int pin1, pin2;
+
+       switch (id) {
+       case BUCK1:
+               if (mode == EXTPIN) {
+                       b1_dvs = (struct lp8788_buck1_dvs *)buck->dvs;
+                       if (!b1_dvs)
+                               goto err;
+
+                       idx = gpio_get_value(b1_dvs->gpio) ? 1 : 0;
+               } else {
+                       lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
+                       idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S;
+               }
+               addr = buck1_vout_addr[idx];
+               break;
+       case BUCK2:
+               if (mode == EXTPIN) {
+                       b2_dvs = (struct lp8788_buck2_dvs *)buck->dvs;
+                       if (!b2_dvs)
+                               goto err;
+
+                       pin1 = gpio_get_value(b2_dvs->gpio[0]);
+                       pin2 = gpio_get_value(b2_dvs->gpio[1]);
+
+                       if (pin1 == PIN_LOW && pin2 == PIN_LOW)
+                               idx = 0;
+                       else if (pin1 == PIN_LOW && pin2 == PIN_HIGH)
+                               idx = 2;
+                       else if (pin1 == PIN_HIGH && pin2 == PIN_LOW)
+                               idx = 1;
+                       else
+                               idx = 3;
+               } else {
+                       lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val);
+                       idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S;
+               }
+               addr = buck2_vout_addr[idx];
+               break;
+       default:
+               goto err;
+       }
+
+       return addr;
+err:
+       return INVALID_ADDR;
+}
+
+static int lp8788_buck12_set_voltage_sel(struct regulator_dev *rdev,
+                                       unsigned selector)
+{
+       struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+       enum lp8788_buck_id id = rdev_get_id(rdev);
+       u8 addr;
+
+       if (buck->dvs)
+               lp8788_set_dvs(buck, id);
+
+       addr = lp8788_select_buck_vout_addr(buck, id);
+       if (!lp8788_is_valid_buck_addr(addr))
+               return -EINVAL;
+
+       return lp8788_update_bits(buck->lp, addr, LP8788_VOUT_M, selector);
+}
+
+static int lp8788_buck12_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+       enum lp8788_buck_id id = rdev_get_id(rdev);
+       int ret;
+       u8 val, addr;
+
+       addr = lp8788_select_buck_vout_addr(buck, id);
+       if (!lp8788_is_valid_buck_addr(addr))
+               return -EINVAL;
+
+       ret = lp8788_read_byte(buck->lp, addr, &val);
+       if (ret)
+               return ret;
+
+       return val & LP8788_VOUT_M;
+}
+
+static int lp8788_buck_enable_time(struct regulator_dev *rdev)
+{
+       struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+       enum lp8788_buck_id id = rdev_get_id(rdev);
+       u8 val, addr = LP8788_BUCK1_TIMESTEP + id;
+
+       if (lp8788_read_byte(buck->lp, addr, &val))
+               return -EINVAL;
+
+       val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
+
+       return ENABLE_TIME_USEC * val;
+}
+
+static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+       struct lp8788_pwm_map *pmap = buck->pmap;
+       u8 val;
+
+       if (!pmap)
+               return -EINVAL;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               val = LP8788_FORCE_PWM << pmap->shift;
+               break;
+       case REGULATOR_MODE_NORMAL:
+               val = LP8788_AUTO_PWM << pmap->shift;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val);
+}
+
+static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
+{
+       struct lp8788_buck *buck = rdev_get_drvdata(rdev);
+       struct lp8788_pwm_map *pmap = buck->pmap;
+       u8 val;
+       int ret;
+
+       if (!pmap)
+               return -EINVAL;
+
+       ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
+       if (ret)
+               return ret;
+
+       return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops lp8788_buck12_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = lp8788_buck12_set_voltage_sel,
+       .get_voltage_sel = lp8788_buck12_get_voltage_sel,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable_time = lp8788_buck_enable_time,
+       .set_mode = lp8788_buck_set_mode,
+       .get_mode = lp8788_buck_get_mode,
+};
+
+static struct regulator_ops lp8788_buck34_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable_time = lp8788_buck_enable_time,
+       .set_mode = lp8788_buck_set_mode,
+       .get_mode = lp8788_buck_get_mode,
+};
+
+static struct regulator_desc lp8788_buck_desc[] = {
+       {
+               .name = "buck1",
+               .id = BUCK1,
+               .ops = &lp8788_buck12_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+               .volt_table = lp8788_buck_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_BUCK,
+               .enable_mask = LP8788_EN_BUCK1_M,
+       },
+       {
+               .name = "buck2",
+               .id = BUCK2,
+               .ops = &lp8788_buck12_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+               .volt_table = lp8788_buck_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_BUCK,
+               .enable_mask = LP8788_EN_BUCK2_M,
+       },
+       {
+               .name = "buck3",
+               .id = BUCK3,
+               .ops = &lp8788_buck34_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+               .volt_table = lp8788_buck_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_BUCK3_VOUT,
+               .vsel_mask = LP8788_VOUT_M,
+               .enable_reg = LP8788_EN_BUCK,
+               .enable_mask = LP8788_EN_BUCK3_M,
+       },
+       {
+               .name = "buck4",
+               .id = BUCK4,
+               .ops = &lp8788_buck34_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_buck_vtbl),
+               .volt_table = lp8788_buck_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_BUCK4_VOUT,
+               .vsel_mask = LP8788_VOUT_M,
+               .enable_reg = LP8788_EN_BUCK,
+               .enable_mask = LP8788_EN_BUCK4_M,
+       },
+};
+
+static int lp8788_set_default_dvs_ctrl_mode(struct lp8788 *lp,
+                                       enum lp8788_buck_id id)
+{
+       u8 mask, val;
+
+       switch (id) {
+       case BUCK1:
+               mask = LP8788_BUCK1_DVS_SEL_M;
+               val  = LP8788_BUCK1_DVS_I2C;
+               break;
+       case BUCK2:
+               mask = LP8788_BUCK2_DVS_SEL_M;
+               val  = LP8788_BUCK2_DVS_I2C;
+               break;
+       default:
+               return 0;
+       }
+
+       return lp8788_update_bits(lp, LP8788_BUCK_DVS_SEL, mask, val);
+}
+
+static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name)
+{
+       struct device *dev = buck->lp->dev;
+
+       if (!gpio_is_valid(gpio)) {
+               dev_err(dev, "invalid gpio: %d\n", gpio);
+               return -EINVAL;
+       }
+
+       return devm_gpio_request_one(dev, gpio, DVS_LOW, name);
+}
+
+static int lp8788_dvs_gpio_request(struct lp8788_buck *buck,
+                               enum lp8788_buck_id id)
+{
+       struct lp8788_platform_data *pdata = buck->lp->pdata;
+       char *b1_name = "LP8788_B1_DVS";
+       char *b2_name[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" };
+       int i, gpio, ret;
+
+       switch (id) {
+       case BUCK1:
+               gpio = pdata->buck1_dvs->gpio;
+               ret = _gpio_request(buck, gpio, b1_name);
+               if (ret)
+                       return ret;
+
+               buck->dvs = pdata->buck1_dvs;
+               break;
+       case BUCK2:
+               for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) {
+                       gpio = pdata->buck2_dvs->gpio[i];
+                       ret = _gpio_request(buck, gpio, b2_name[i]);
+                       if (ret)
+                               return ret;
+               }
+               buck->dvs = pdata->buck2_dvs;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
+{
+       struct lp8788_platform_data *pdata = buck->lp->pdata;
+       u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
+       u8 val[]  = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
+
+       /* no dvs for buck3, 4 */
+       if (id == BUCK3 || id == BUCK4)
+               return 0;
+
+       /* no dvs platform data, then dvs will be selected by I2C registers */
+       if (!pdata)
+               goto set_default_dvs_mode;
+
+       if ((id == BUCK1 && !pdata->buck1_dvs) ||
+               (id == BUCK2 && !pdata->buck2_dvs))
+               goto set_default_dvs_mode;
+
+       if (lp8788_dvs_gpio_request(buck, id))
+               goto set_default_dvs_mode;
+
+       return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
+                               val[id]);
+
+set_default_dvs_mode:
+       return lp8788_set_default_dvs_ctrl_mode(buck->lp, id);
+}
+
+static __devinit int lp8788_buck_probe(struct platform_device *pdev)
+{
+       struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+       int id = pdev->id;
+       struct lp8788_buck *buck;
+       struct regulator_config cfg = { };
+       struct regulator_dev *rdev;
+       int ret;
+
+       buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL);
+       if (!buck)
+               return -ENOMEM;
+
+       buck->lp = lp;
+       buck->pmap = &buck_pmap[id];
+
+       ret = lp8788_init_dvs(buck, id);
+       if (ret)
+               return ret;
+
+       cfg.dev = lp->dev;
+       cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL;
+       cfg.driver_data = buck;
+       cfg.regmap = lp->regmap;
+
+       rdev = regulator_register(&lp8788_buck_desc[id], &cfg);
+       if (IS_ERR(rdev)) {
+               ret = PTR_ERR(rdev);
+               dev_err(lp->dev, "BUCK%d regulator register err = %d\n",
+                               id + 1, ret);
+               return ret;
+       }
+
+       buck->regulator = rdev;
+       platform_set_drvdata(pdev, buck);
+
+       return 0;
+}
+
+static int __devexit lp8788_buck_remove(struct platform_device *pdev)
+{
+       struct lp8788_buck *buck = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       regulator_unregister(buck->regulator);
+
+       return 0;
+}
+
+static struct platform_driver lp8788_buck_driver = {
+       .probe = lp8788_buck_probe,
+       .remove = __devexit_p(lp8788_buck_remove),
+       .driver = {
+               .name = LP8788_DEV_BUCK,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init lp8788_buck_init(void)
+{
+       return platform_driver_register(&lp8788_buck_driver);
+}
+subsys_initcall(lp8788_buck_init);
+
+static void __exit lp8788_buck_exit(void)
+{
+       platform_driver_unregister(&lp8788_buck_driver);
+}
+module_exit(lp8788_buck_exit);
+
+MODULE_DESCRIPTION("TI LP8788 BUCK Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp8788-buck");
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
new file mode 100644 (file)
index 0000000..d2122e4
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * TI LP8788 MFD - ldo regulator driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@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/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/gpio.h>
+#include <linux/mfd/lp8788.h>
+
+/* register address */
+#define LP8788_EN_LDO_A                        0x0D    /* DLDO 1 ~ 8 */
+#define LP8788_EN_LDO_B                        0x0E    /* DLDO 9 ~ 12, ALDO 1 ~ 4 */
+#define LP8788_EN_LDO_C                        0x0F    /* ALDO 5 ~ 10 */
+#define LP8788_EN_SEL                  0x10
+#define LP8788_DLDO1_VOUT              0x2E
+#define LP8788_DLDO2_VOUT              0x2F
+#define LP8788_DLDO3_VOUT              0x30
+#define LP8788_DLDO4_VOUT              0x31
+#define LP8788_DLDO5_VOUT              0x32
+#define LP8788_DLDO6_VOUT              0x33
+#define LP8788_DLDO7_VOUT              0x34
+#define LP8788_DLDO8_VOUT              0x35
+#define LP8788_DLDO9_VOUT              0x36
+#define LP8788_DLDO10_VOUT             0x37
+#define LP8788_DLDO11_VOUT             0x38
+#define LP8788_DLDO12_VOUT             0x39
+#define LP8788_ALDO1_VOUT              0x3A
+#define LP8788_ALDO2_VOUT              0x3B
+#define LP8788_ALDO3_VOUT              0x3C
+#define LP8788_ALDO4_VOUT              0x3D
+#define LP8788_ALDO5_VOUT              0x3E
+#define LP8788_ALDO6_VOUT              0x3F
+#define LP8788_ALDO7_VOUT              0x40
+#define LP8788_ALDO8_VOUT              0x41
+#define LP8788_ALDO9_VOUT              0x42
+#define LP8788_ALDO10_VOUT             0x43
+#define LP8788_DLDO1_TIMESTEP          0x44
+
+/* mask/shift bits */
+#define LP8788_EN_DLDO1_M              BIT(0)  /* Addr 0Dh ~ 0Fh */
+#define LP8788_EN_DLDO2_M              BIT(1)
+#define LP8788_EN_DLDO3_M              BIT(2)
+#define LP8788_EN_DLDO4_M              BIT(3)
+#define LP8788_EN_DLDO5_M              BIT(4)
+#define LP8788_EN_DLDO6_M              BIT(5)
+#define LP8788_EN_DLDO7_M              BIT(6)
+#define LP8788_EN_DLDO8_M              BIT(7)
+#define LP8788_EN_DLDO9_M              BIT(0)
+#define LP8788_EN_DLDO10_M             BIT(1)
+#define LP8788_EN_DLDO11_M             BIT(2)
+#define LP8788_EN_DLDO12_M             BIT(3)
+#define LP8788_EN_ALDO1_M              BIT(4)
+#define LP8788_EN_ALDO2_M              BIT(5)
+#define LP8788_EN_ALDO3_M              BIT(6)
+#define LP8788_EN_ALDO4_M              BIT(7)
+#define LP8788_EN_ALDO5_M              BIT(0)
+#define LP8788_EN_ALDO6_M              BIT(1)
+#define LP8788_EN_ALDO7_M              BIT(2)
+#define LP8788_EN_ALDO8_M              BIT(3)
+#define LP8788_EN_ALDO9_M              BIT(4)
+#define LP8788_EN_ALDO10_M             BIT(5)
+#define LP8788_EN_SEL_DLDO911_M                BIT(0)  /* Addr 10h */
+#define LP8788_EN_SEL_DLDO7_M          BIT(1)
+#define LP8788_EN_SEL_ALDO7_M          BIT(2)
+#define LP8788_EN_SEL_ALDO5_M          BIT(3)
+#define LP8788_EN_SEL_ALDO234_M                BIT(4)
+#define LP8788_EN_SEL_ALDO1_M          BIT(5)
+#define LP8788_VOUT_5BIT_M             0x1F    /* Addr 2Eh ~ 43h */
+#define LP8788_VOUT_4BIT_M             0x0F
+#define LP8788_VOUT_3BIT_M             0x07
+#define LP8788_VOUT_1BIT_M             0x01
+#define LP8788_STARTUP_TIME_M          0xF8    /* Addr 44h ~ 59h */
+#define LP8788_STARTUP_TIME_S          3
+
+#define ENABLE_TIME_USEC               32
+#define ENABLE                         GPIOF_OUT_INIT_HIGH
+#define DISABLE                                GPIOF_OUT_INIT_LOW
+
+enum lp8788_enable_mode {
+       REGISTER,
+       EXTPIN,
+};
+
+enum lp8788_ldo_id {
+       DLDO1,
+       DLDO2,
+       DLDO3,
+       DLDO4,
+       DLDO5,
+       DLDO6,
+       DLDO7,
+       DLDO8,
+       DLDO9,
+       DLDO10,
+       DLDO11,
+       DLDO12,
+       ALDO1,
+       ALDO2,
+       ALDO3,
+       ALDO4,
+       ALDO5,
+       ALDO6,
+       ALDO7,
+       ALDO8,
+       ALDO9,
+       ALDO10,
+};
+
+struct lp8788_ldo {
+       struct lp8788 *lp;
+       struct regulator_desc *desc;
+       struct regulator_dev *regulator;
+       struct lp8788_ldo_enable_pin *en_pin;
+};
+
+/* DLDO 1, 2, 3, 9 voltage table */
+const int lp8788_dldo1239_vtbl[] = {
+       1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+       2600000, 2700000, 2800000, 2900000, 3000000, 2850000, 2850000, 2850000,
+       2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000,
+       2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000, 2850000,
+};
+
+/* DLDO 4 voltage table */
+static const int lp8788_dldo4_vtbl[] = { 1800000, 3000000 };
+
+/* DLDO 5, 7, 8 and ALDO 6 voltage table */
+static const int lp8788_dldo578_aldo6_vtbl[] = {
+       1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+       2600000, 2700000, 2800000, 2900000, 3000000, 3000000, 3000000, 3000000,
+};
+
+/* DLDO 6 voltage table */
+static const int lp8788_dldo6_vtbl[] = {
+       3000000, 3100000, 3200000, 3300000, 3400000, 3500000, 3600000, 3600000,
+};
+
+/* DLDO 10, 11 voltage table */
+static const int lp8788_dldo1011_vtbl[] = {
+       1100000, 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000,
+       1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000, 1500000,
+};
+
+/* ALDO 1 voltage table */
+static const int lp8788_aldo1_vtbl[] = { 1800000, 2850000 };
+
+/* ALDO 7 voltage table */
+static const int lp8788_aldo7_vtbl[] = {
+       1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1800000,
+};
+
+static enum lp8788_ldo_id lp8788_dldo_id[] = {
+       DLDO1,
+       DLDO2,
+       DLDO3,
+       DLDO4,
+       DLDO5,
+       DLDO6,
+       DLDO7,
+       DLDO8,
+       DLDO9,
+       DLDO10,
+       DLDO11,
+       DLDO12,
+};
+
+static enum lp8788_ldo_id lp8788_aldo_id[] = {
+       ALDO1,
+       ALDO2,
+       ALDO3,
+       ALDO4,
+       ALDO5,
+       ALDO6,
+       ALDO7,
+       ALDO8,
+       ALDO9,
+       ALDO10,
+};
+
+/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7
+   : can be enabled either by external pin or by i2c register */
+static enum lp8788_enable_mode
+lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id)
+{
+       int ret;
+       u8 val, mask;
+
+       ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val);
+       if (ret)
+               return ret;
+
+       switch (id) {
+       case DLDO7:
+               mask =  LP8788_EN_SEL_DLDO7_M;
+               break;
+       case DLDO9:
+       case DLDO11:
+               mask =  LP8788_EN_SEL_DLDO911_M;
+               break;
+       case ALDO1:
+               mask =  LP8788_EN_SEL_ALDO1_M;
+               break;
+       case ALDO2 ... ALDO4:
+               mask =  LP8788_EN_SEL_ALDO234_M;
+               break;
+       case ALDO5:
+               mask =  LP8788_EN_SEL_ALDO5_M;
+               break;
+       case ALDO7:
+               mask =  LP8788_EN_SEL_ALDO7_M;
+               break;
+       default:
+               return REGISTER;
+       }
+
+       return val & mask ? EXTPIN : REGISTER;
+}
+
+static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate)
+{
+       struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
+
+       if (!pin)
+               return -EINVAL;
+
+       if (gpio_is_valid(pin->gpio))
+               gpio_set_value(pin->gpio, pinstate);
+
+       return 0;
+}
+
+static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo)
+{
+       struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
+
+       if (!pin)
+               return -EINVAL;
+
+       return gpio_get_value(pin->gpio) ? 1 : 0;
+}
+
+static int lp8788_ldo_enable(struct regulator_dev *rdev)
+{
+       struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+       enum lp8788_ldo_id id = rdev_get_id(rdev);
+       enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
+
+       switch (mode) {
+       case EXTPIN:
+               return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE);
+       case REGISTER:
+               return regulator_enable_regmap(rdev);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int lp8788_ldo_disable(struct regulator_dev *rdev)
+{
+       struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+       enum lp8788_ldo_id id = rdev_get_id(rdev);
+       enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
+
+       switch (mode) {
+       case EXTPIN:
+               return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE);
+       case REGISTER:
+               return regulator_disable_regmap(rdev);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
+{
+       struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+       enum lp8788_ldo_id id = rdev_get_id(rdev);
+       enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id);
+
+       switch (mode) {
+       case EXTPIN:
+               return lp8788_ldo_is_enabled_by_extern_pin(ldo);
+       case REGISTER:
+               return regulator_is_enabled_regmap(rdev);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
+{
+       struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
+       enum lp8788_ldo_id id = rdev_get_id(rdev);
+       u8 val, addr = LP8788_DLDO1_TIMESTEP + id;
+
+       if (lp8788_read_byte(ldo->lp, addr, &val))
+               return -EINVAL;
+
+       val = (val & LP8788_STARTUP_TIME_M) >> LP8788_STARTUP_TIME_S;
+
+       return ENABLE_TIME_USEC * val;
+}
+
+static int lp8788_ldo_fixed_get_voltage(struct regulator_dev *rdev)
+{
+       enum lp8788_ldo_id id = rdev_get_id(rdev);
+
+       switch (id) {
+       case ALDO2 ... ALDO5:
+               return 2850000;
+       case DLDO12:
+       case ALDO8 ... ALDO9:
+               return 2500000;
+       case ALDO10:
+               return 1100000;
+       default:
+               return -EINVAL;
+       }
+}
+
+static struct regulator_ops lp8788_ldo_voltage_table_ops = {
+       .list_voltage = regulator_list_voltage_table,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .enable = lp8788_ldo_enable,
+       .disable = lp8788_ldo_disable,
+       .is_enabled = lp8788_ldo_is_enabled,
+       .enable_time = lp8788_ldo_enable_time,
+};
+
+static struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
+       .get_voltage = lp8788_ldo_fixed_get_voltage,
+       .enable = lp8788_ldo_enable,
+       .disable = lp8788_ldo_disable,
+       .is_enabled = lp8788_ldo_is_enabled,
+       .enable_time = lp8788_ldo_enable_time,
+};
+
+static struct regulator_desc lp8788_dldo_desc[] = {
+       {
+               .name = "dldo1",
+               .id = DLDO1,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+               .volt_table = lp8788_dldo1239_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO1_VOUT,
+               .vsel_mask = LP8788_VOUT_5BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO1_M,
+       },
+       {
+               .name = "dldo2",
+               .id = DLDO2,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+               .volt_table = lp8788_dldo1239_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO2_VOUT,
+               .vsel_mask = LP8788_VOUT_5BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO2_M,
+       },
+       {
+               .name = "dldo3",
+               .id = DLDO3,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+               .volt_table = lp8788_dldo1239_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO3_VOUT,
+               .vsel_mask = LP8788_VOUT_5BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO3_M,
+       },
+       {
+               .name = "dldo4",
+               .id = DLDO4,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo4_vtbl),
+               .volt_table = lp8788_dldo4_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO4_VOUT,
+               .vsel_mask = LP8788_VOUT_1BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO4_M,
+       },
+       {
+               .name = "dldo5",
+               .id = DLDO5,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+               .volt_table = lp8788_dldo578_aldo6_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO5_VOUT,
+               .vsel_mask = LP8788_VOUT_4BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO5_M,
+       },
+       {
+               .name = "dldo6",
+               .id = DLDO6,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo6_vtbl),
+               .volt_table = lp8788_dldo6_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO6_VOUT,
+               .vsel_mask = LP8788_VOUT_3BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO6_M,
+       },
+       {
+               .name = "dldo7",
+               .id = DLDO7,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+               .volt_table = lp8788_dldo578_aldo6_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO7_VOUT,
+               .vsel_mask = LP8788_VOUT_4BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO7_M,
+       },
+       {
+               .name = "dldo8",
+               .id = DLDO8,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+               .volt_table = lp8788_dldo578_aldo6_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO8_VOUT,
+               .vsel_mask = LP8788_VOUT_4BIT_M,
+               .enable_reg = LP8788_EN_LDO_A,
+               .enable_mask = LP8788_EN_DLDO8_M,
+       },
+       {
+               .name = "dldo9",
+               .id = DLDO9,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo1239_vtbl),
+               .volt_table = lp8788_dldo1239_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO9_VOUT,
+               .vsel_mask = LP8788_VOUT_5BIT_M,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_DLDO9_M,
+       },
+       {
+               .name = "dldo10",
+               .id = DLDO10,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl),
+               .volt_table = lp8788_dldo1011_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO10_VOUT,
+               .vsel_mask = LP8788_VOUT_4BIT_M,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_DLDO10_M,
+       },
+       {
+               .name = "dldo11",
+               .id = DLDO11,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo1011_vtbl),
+               .volt_table = lp8788_dldo1011_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_DLDO11_VOUT,
+               .vsel_mask = LP8788_VOUT_4BIT_M,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_DLDO11_M,
+       },
+       {
+               .name = "dldo12",
+               .id = DLDO12,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_DLDO12_M,
+       },
+};
+
+static struct regulator_desc lp8788_aldo_desc[] = {
+       {
+               .name = "aldo1",
+               .id = ALDO1,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_aldo1_vtbl),
+               .volt_table = lp8788_aldo1_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_ALDO1_VOUT,
+               .vsel_mask = LP8788_VOUT_1BIT_M,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_ALDO1_M,
+       },
+       {
+               .name = "aldo2",
+               .id = ALDO2,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_ALDO2_M,
+       },
+       {
+               .name = "aldo3",
+               .id = ALDO3,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_ALDO3_M,
+       },
+       {
+               .name = "aldo4",
+               .id = ALDO4,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_B,
+               .enable_mask = LP8788_EN_ALDO4_M,
+       },
+       {
+               .name = "aldo5",
+               .id = ALDO5,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_C,
+               .enable_mask = LP8788_EN_ALDO5_M,
+       },
+       {
+               .name = "aldo6",
+               .id = ALDO6,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_dldo578_aldo6_vtbl),
+               .volt_table = lp8788_dldo578_aldo6_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_ALDO6_VOUT,
+               .vsel_mask = LP8788_VOUT_4BIT_M,
+               .enable_reg = LP8788_EN_LDO_C,
+               .enable_mask = LP8788_EN_ALDO6_M,
+       },
+       {
+               .name = "aldo7",
+               .id = ALDO7,
+               .ops = &lp8788_ldo_voltage_table_ops,
+               .n_voltages = ARRAY_SIZE(lp8788_aldo7_vtbl),
+               .volt_table = lp8788_aldo7_vtbl,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .vsel_reg = LP8788_ALDO7_VOUT,
+               .vsel_mask = LP8788_VOUT_3BIT_M,
+               .enable_reg = LP8788_EN_LDO_C,
+               .enable_mask = LP8788_EN_ALDO7_M,
+       },
+       {
+               .name = "aldo8",
+               .id = ALDO8,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_C,
+               .enable_mask = LP8788_EN_ALDO8_M,
+       },
+       {
+               .name = "aldo9",
+               .id = ALDO9,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_C,
+               .enable_mask = LP8788_EN_ALDO9_M,
+       },
+       {
+               .name = "aldo10",
+               .id = ALDO10,
+               .ops = &lp8788_ldo_voltage_fixed_ops,
+               .type = REGULATOR_VOLTAGE,
+               .owner = THIS_MODULE,
+               .enable_reg = LP8788_EN_LDO_C,
+               .enable_mask = LP8788_EN_ALDO10_M,
+       },
+};
+
+static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo,
+                               enum lp8788_ext_ldo_en_id id)
+{
+       struct device *dev = ldo->lp->dev;
+       struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
+       int ret, gpio, pinstate;
+       char *name[] = {
+               [EN_ALDO1]   = "LP8788_EN_ALDO1",
+               [EN_ALDO234] = "LP8788_EN_ALDO234",
+               [EN_ALDO5]   = "LP8788_EN_ALDO5",
+               [EN_ALDO7]   = "LP8788_EN_ALDO7",
+               [EN_DLDO7]   = "LP8788_EN_DLDO7",
+               [EN_DLDO911] = "LP8788_EN_DLDO911",
+       };
+
+       gpio = pin->gpio;
+       if (!gpio_is_valid(gpio)) {
+               dev_err(dev, "invalid gpio: %d\n", gpio);
+               return -EINVAL;
+       }
+
+       pinstate = pin->init_state;
+       ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]);
+       if (ret == -EBUSY) {
+               dev_warn(dev, "gpio%d already used\n", gpio);
+               return 0;
+       }
+
+       return ret;
+}
+
+static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo,
+                                       enum lp8788_ldo_id id)
+{
+       int ret;
+       struct lp8788 *lp = ldo->lp;
+       struct lp8788_platform_data *pdata = lp->pdata;
+       enum lp8788_ext_ldo_en_id enable_id;
+       u8 en_mask[] = {
+               [EN_ALDO1]   = LP8788_EN_SEL_ALDO1_M,
+               [EN_ALDO234] = LP8788_EN_SEL_ALDO234_M,
+               [EN_ALDO5]   = LP8788_EN_SEL_ALDO5_M,
+               [EN_ALDO7]   = LP8788_EN_SEL_ALDO7_M,
+               [EN_DLDO7]   = LP8788_EN_SEL_DLDO7_M,
+               [EN_DLDO911] = LP8788_EN_SEL_DLDO911_M,
+       };
+       u8 val[] = {
+               [EN_ALDO1]   = 0 << 5,
+               [EN_ALDO234] = 0 << 4,
+               [EN_ALDO5]   = 0 << 3,
+               [EN_ALDO7]   = 0 << 2,
+               [EN_DLDO7]   = 0 << 1,
+               [EN_DLDO911] = 0 << 0,
+       };
+
+       switch (id) {
+       case DLDO7:
+               enable_id = EN_DLDO7;
+               break;
+       case DLDO9:
+       case DLDO11:
+               enable_id = EN_DLDO911;
+               break;
+       case ALDO1:
+               enable_id = EN_ALDO1;
+               break;
+       case ALDO2 ... ALDO4:
+               enable_id = EN_ALDO234;
+               break;
+       case ALDO5:
+               enable_id = EN_ALDO5;
+               break;
+       case ALDO7:
+               enable_id = EN_ALDO7;
+               break;
+       default:
+               return 0;
+       }
+
+       /* if no platform data for ldo pin, then set default enable mode */
+       if (!pdata || !pdata->ldo_pin || !pdata->ldo_pin[enable_id])
+               goto set_default_ldo_enable_mode;
+
+       ldo->en_pin = pdata->ldo_pin[enable_id];
+
+       ret = lp8788_gpio_request_ldo_en(ldo, enable_id);
+       if (ret)
+               goto set_default_ldo_enable_mode;
+
+       return ret;
+
+set_default_ldo_enable_mode:
+       return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id],
+                               val[enable_id]);
+}
+
+static __devinit int lp8788_dldo_probe(struct platform_device *pdev)
+{
+       struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+       int id = pdev->id;
+       struct lp8788_ldo *ldo;
+       struct regulator_config cfg = { };
+       struct regulator_dev *rdev;
+       int ret;
+
+       ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+       if (!ldo)
+               return -ENOMEM;
+
+       ldo->lp = lp;
+       ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]);
+       if (ret)
+               return ret;
+
+       cfg.dev = lp->dev;
+       cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
+       cfg.driver_data = ldo;
+       cfg.regmap = lp->regmap;
+
+       rdev = regulator_register(&lp8788_dldo_desc[id], &cfg);
+       if (IS_ERR(rdev)) {
+               ret = PTR_ERR(rdev);
+               dev_err(lp->dev, "DLDO%d regulator register err = %d\n",
+                               id + 1, ret);
+               return ret;
+       }
+
+       ldo->regulator = rdev;
+       platform_set_drvdata(pdev, ldo);
+
+       return 0;
+}
+
+static int __devexit lp8788_dldo_remove(struct platform_device *pdev)
+{
+       struct lp8788_ldo *ldo = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       regulator_unregister(ldo->regulator);
+
+       return 0;
+}
+
+static struct platform_driver lp8788_dldo_driver = {
+       .probe = lp8788_dldo_probe,
+       .remove = __devexit_p(lp8788_dldo_remove),
+       .driver = {
+               .name = LP8788_DEV_DLDO,
+               .owner = THIS_MODULE,
+       },
+};
+
+static __devinit int lp8788_aldo_probe(struct platform_device *pdev)
+{
+       struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+       int id = pdev->id;
+       struct lp8788_ldo *ldo;
+       struct regulator_config cfg = { };
+       struct regulator_dev *rdev;
+       int ret;
+
+       ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL);
+       if (!ldo)
+               return -ENOMEM;
+
+       ldo->lp = lp;
+       ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]);
+       if (ret)
+               return ret;
+
+       cfg.dev = lp->dev;
+       cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
+       cfg.driver_data = ldo;
+       cfg.regmap = lp->regmap;
+
+       rdev = regulator_register(&lp8788_aldo_desc[id], &cfg);
+       if (IS_ERR(rdev)) {
+               ret = PTR_ERR(rdev);
+               dev_err(lp->dev, "ALDO%d regulator register err = %d\n",
+                               id + 1, ret);
+               return ret;
+       }
+
+       ldo->regulator = rdev;
+       platform_set_drvdata(pdev, ldo);
+
+       return 0;
+}
+
+static int __devexit lp8788_aldo_remove(struct platform_device *pdev)
+{
+       struct lp8788_ldo *ldo = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       regulator_unregister(ldo->regulator);
+
+       return 0;
+}
+
+static struct platform_driver lp8788_aldo_driver = {
+       .probe = lp8788_aldo_probe,
+       .remove = __devexit_p(lp8788_aldo_remove),
+       .driver = {
+               .name = LP8788_DEV_ALDO,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init lp8788_ldo_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&lp8788_dldo_driver);
+       if (ret)
+               return ret;
+
+       return platform_driver_register(&lp8788_aldo_driver);
+}
+subsys_initcall(lp8788_ldo_init);
+
+static void __exit lp8788_ldo_exit(void)
+{
+       platform_driver_unregister(&lp8788_aldo_driver);
+       platform_driver_unregister(&lp8788_dldo_driver);
+}
+module_exit(lp8788_ldo_exit);
+
+MODULE_DESCRIPTION("TI LP8788 LDO Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp8788-dldo");
+MODULE_ALIAS("platform:lp8788-aldo");
index b9444ee08da9d27af4ec3d9e632e21b75eefa394..f67af3c1b9638636f5bdde781d15b79d516b89e8 100644 (file)
@@ -47,6 +47,14 @@ struct max1586_data {
        struct regulator_dev *rdev[0];
 };
 
+/*
+ * V6 voltage
+ * On I2C bus, sending a "x" byte to the max1586 means :
+ *   set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
+ * As regulator framework doesn't accept voltages to be 0V, we use 1uV.
+ */
+static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
+
 /*
  * V3 voltage
  * On I2C bus, sending a "x" byte to the max1586 means :
@@ -55,113 +63,49 @@ struct max1586_data {
  * R24 and R25=100kOhm as described in the data sheet.
  * The gain is approximately: 1 + R24/R25 + R24/185.5kOhm
  */
-static int max1586_v3_calc_voltage(struct max1586_data *max1586,
-       unsigned selector)
-{
-       unsigned range_uV = max1586->max_uV - max1586->min_uV;
-
-       return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL);
-}
-
-static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV,
-                         unsigned *selector)
+static int max1586_v3_set_voltage_sel(struct regulator_dev *rdev,
+                                     unsigned selector)
 {
        struct max1586_data *max1586 = rdev_get_drvdata(rdev);
        struct i2c_client *client = max1586->client;
-       unsigned range_uV = max1586->max_uV - max1586->min_uV;
        u8 v3_prog;
 
-       if (min_uV > max1586->max_uV || max_uV < max1586->min_uV)
-               return -EINVAL;
-       if (min_uV < max1586->min_uV)
-               min_uV = max1586->min_uV;
-
-       *selector = DIV_ROUND_UP((min_uV - max1586->min_uV) *
-                                MAX1586_V3_MAX_VSEL, range_uV);
-       if (max1586_v3_calc_voltage(max1586, *selector) > max_uV)
-               return -EINVAL;
-
        dev_dbg(&client->dev, "changing voltage v3 to %dmv\n",
-               max1586_v3_calc_voltage(max1586, *selector) / 1000);
+               regulator_list_voltage_linear(rdev, selector) / 1000);
 
-       v3_prog = I2C_V3_SELECT | (u8) *selector;
+       v3_prog = I2C_V3_SELECT | (u8) selector;
        return i2c_smbus_write_byte(client, v3_prog);
 }
 
-static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector)
-{
-       struct max1586_data *max1586 = rdev_get_drvdata(rdev);
-
-       if (selector > MAX1586_V3_MAX_VSEL)
-               return -EINVAL;
-       return max1586_v3_calc_voltage(max1586, selector);
-}
-
-/*
- * V6 voltage
- * On I2C bus, sending a "x" byte to the max1586 means :
- *   set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
- * As regulator framework doesn't accept voltages to be 0V, we use 1uV.
- */
-static int max1586_v6_calc_voltage(unsigned selector)
-{
-       static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
-
-       return voltages_uv[selector];
-}
-
-static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV,
-                         unsigned int *selector)
+static int max1586_v6_set_voltage_sel(struct regulator_dev *rdev,
+                                     unsigned int selector)
 {
        struct i2c_client *client = rdev_get_drvdata(rdev);
        u8 v6_prog;
 
-       if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV)
-               return -EINVAL;
-       if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV)
-               return -EINVAL;
-
-       if (min_uV < 1800000)
-               *selector = 0;
-       else if (min_uV < 2500000)
-               *selector = 1;
-       else if (min_uV < 3000000)
-               *selector = 2;
-       else if (min_uV >= 3000000)
-               *selector = 3;
-
-       if (max1586_v6_calc_voltage(*selector) > max_uV)
-               return -EINVAL;
-
        dev_dbg(&client->dev, "changing voltage v6 to %dmv\n",
-               max1586_v6_calc_voltage(*selector) / 1000);
+               rdev->desc->volt_table[selector] / 1000);
 
-       v6_prog = I2C_V6_SELECT | (u8) *selector;
+       v6_prog = I2C_V6_SELECT | (u8) selector;
        return i2c_smbus_write_byte(client, v6_prog);
 }
 
-static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector)
-{
-       if (selector > MAX1586_V6_MAX_VSEL)
-               return -EINVAL;
-       return max1586_v6_calc_voltage(selector);
-}
-
 /*
  * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back
  * the set up value.
  */
 static struct regulator_ops max1586_v3_ops = {
-       .set_voltage = max1586_v3_set,
-       .list_voltage = max1586_v3_list,
+       .set_voltage_sel = max1586_v3_set_voltage_sel,
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
 };
 
 static struct regulator_ops max1586_v6_ops = {
-       .set_voltage = max1586_v6_set,
-       .list_voltage = max1586_v6_list,
+       .set_voltage_sel = max1586_v6_set_voltage_sel,
+       .list_voltage = regulator_list_voltage_table,
 };
 
-static const struct regulator_desc max1586_reg[] = {
+static struct regulator_desc max1586_reg[] = {
        {
                .name = "Output_V3",
                .id = MAX1586_V3,
@@ -176,6 +120,7 @@ static const struct regulator_desc max1586_reg[] = {
                .ops = &max1586_v6_ops,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = MAX1586_V6_MAX_VSEL + 1,
+               .volt_table = v6_voltages_uv,
                .owner = THIS_MODULE,
        },
 };
@@ -213,6 +158,13 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client,
                        goto err;
                }
 
+               if (id == MAX1586_V3) {
+                       max1586_reg[id].min_uV = max1586->min_uV;
+                       max1586_reg[id].uV_step =
+                                       (max1586->max_uV - max1586->min_uV) /
+                                       MAX1586_V3_MAX_VSEL;
+               }
+
                config.dev = &client->dev;
                config.init_data = pdata->subdevs[i].platform_data;
                config.driver_data = max1586;
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
new file mode 100644 (file)
index 0000000..c564af6
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * max77686.c - Regulator driver for the Maxim 77686
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Chiwoong Byun <woong.byun@smasung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is based on max8997.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.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/max77686.h>
+#include <linux/mfd/max77686-private.h>
+
+#define MAX77686_LDO_MINUV     800000
+#define MAX77686_LDO_UVSTEP    50000
+#define MAX77686_LDO_LOW_MINUV 800000
+#define MAX77686_LDO_LOW_UVSTEP        25000
+#define MAX77686_BUCK_MINUV    750000
+#define MAX77686_BUCK_UVSTEP   50000
+#define MAX77686_RAMP_DELAY    100000                  /* uV/us */
+#define MAX77686_DVS_RAMP_DELAY        27500                   /* uV/us */
+#define MAX77686_DVS_MINUV     600000
+#define MAX77686_DVS_UVSTEP    12500
+
+#define MAX77686_OPMODE_SHIFT  6
+#define MAX77686_OPMODE_BUCK234_SHIFT  4
+#define MAX77686_OPMODE_MASK   0x3
+
+#define MAX77686_VSEL_MASK     0x3F
+#define MAX77686_DVS_VSEL_MASK 0xFF
+
+#define MAX77686_RAMP_RATE_MASK        0xC0
+
+#define MAX77686_REGULATORS    MAX77686_REG_MAX
+#define MAX77686_LDOS          26
+
+enum max77686_ramp_rate {
+       RAMP_RATE_13P75MV,
+       RAMP_RATE_27P5MV,
+       RAMP_RATE_55MV,
+       RAMP_RATE_NO_CTRL,      /* 100mV/us */
+};
+
+struct max77686_data {
+       struct regulator_dev **rdev;
+};
+
+static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+       unsigned int ramp_value = RAMP_RATE_NO_CTRL;
+
+       switch (ramp_delay) {
+       case 1 ... 13750:
+               ramp_value = RAMP_RATE_13P75MV;
+               break;
+       case 13751 ... 27500:
+               ramp_value = RAMP_RATE_27P5MV;
+               break;
+       case 27501 ... 55000:
+               ramp_value = RAMP_RATE_55MV;
+               break;
+       case 55001 ... 100000:
+               break;
+       default:
+               pr_warn("%s: ramp_delay: %d not supported, setting 100000\n",
+                       rdev->desc->name, ramp_delay);
+       }
+
+       return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+                                 MAX77686_RAMP_RATE_MASK, ramp_value << 6);
+}
+
+static struct regulator_ops max77686_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 max77686_buck_dvs_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,
+       .set_ramp_delay         = max77686_set_ramp_delay,
+};
+
+#define regulator_desc_ldo(num)                {                               \
+       .name           = "LDO"#num,                                    \
+       .id             = MAX77686_LDO##num,                            \
+       .ops            = &max77686_ops,                                \
+       .type           = REGULATOR_VOLTAGE,                            \
+       .owner          = THIS_MODULE,                                  \
+       .min_uV         = MAX77686_LDO_MINUV,                           \
+       .uV_step        = MAX77686_LDO_UVSTEP,                          \
+       .ramp_delay     = MAX77686_RAMP_DELAY,                          \
+       .n_voltages     = MAX77686_VSEL_MASK + 1,                       \
+       .vsel_reg       = MAX77686_REG_LDO1CTRL1 + num - 1,             \
+       .vsel_mask      = MAX77686_VSEL_MASK,                           \
+       .enable_reg     = MAX77686_REG_LDO1CTRL1 + num - 1,             \
+       .enable_mask    = MAX77686_OPMODE_MASK                          \
+                       << MAX77686_OPMODE_SHIFT,                       \
+}
+#define regulator_desc_ldo_low(num)            {                       \
+       .name           = "LDO"#num,                                    \
+       .id             = MAX77686_LDO##num,                            \
+       .ops            = &max77686_ops,                                \
+       .type           = REGULATOR_VOLTAGE,                            \
+       .owner          = THIS_MODULE,                                  \
+       .min_uV         = MAX77686_LDO_LOW_MINUV,                       \
+       .uV_step        = MAX77686_LDO_LOW_UVSTEP,                      \
+       .ramp_delay     = MAX77686_RAMP_DELAY,                          \
+       .n_voltages     = MAX77686_VSEL_MASK + 1,                       \
+       .vsel_reg       = MAX77686_REG_LDO1CTRL1 + num - 1,             \
+       .vsel_mask      = MAX77686_VSEL_MASK,                           \
+       .enable_reg     = MAX77686_REG_LDO1CTRL1 + num - 1,             \
+       .enable_mask    = MAX77686_OPMODE_MASK                          \
+                       << MAX77686_OPMODE_SHIFT,                       \
+}
+#define regulator_desc_buck(num)               {                       \
+       .name           = "BUCK"#num,                                   \
+       .id             = MAX77686_BUCK##num,                           \
+       .ops            = &max77686_ops,                                \
+       .type           = REGULATOR_VOLTAGE,                            \
+       .owner          = THIS_MODULE,                                  \
+       .min_uV         = MAX77686_BUCK_MINUV,                          \
+       .uV_step        = MAX77686_BUCK_UVSTEP,                         \
+       .ramp_delay     = MAX77686_RAMP_DELAY,                          \
+       .n_voltages     = MAX77686_VSEL_MASK + 1,                       \
+       .vsel_reg       = MAX77686_REG_BUCK5OUT + (num - 5) * 2,        \
+       .vsel_mask      = MAX77686_VSEL_MASK,                           \
+       .enable_reg     = MAX77686_REG_BUCK5CTRL + (num - 5) * 2,       \
+       .enable_mask    = MAX77686_OPMODE_MASK,                         \
+}
+#define regulator_desc_buck1(num)              {                       \
+       .name           = "BUCK"#num,                                   \
+       .id             = MAX77686_BUCK##num,                           \
+       .ops            = &max77686_ops,                                \
+       .type           = REGULATOR_VOLTAGE,                            \
+       .owner          = THIS_MODULE,                                  \
+       .min_uV         = MAX77686_BUCK_MINUV,                          \
+       .uV_step        = MAX77686_BUCK_UVSTEP,                         \
+       .ramp_delay     = MAX77686_RAMP_DELAY,                          \
+       .n_voltages     = MAX77686_VSEL_MASK + 1,                       \
+       .vsel_reg       = MAX77686_REG_BUCK1OUT,                        \
+       .vsel_mask      = MAX77686_VSEL_MASK,                           \
+       .enable_reg     = MAX77686_REG_BUCK1CTRL,                       \
+       .enable_mask    = MAX77686_OPMODE_MASK,                         \
+}
+#define regulator_desc_buck_dvs(num)           {                       \
+       .name           = "BUCK"#num,                                   \
+       .id             = MAX77686_BUCK##num,                           \
+       .ops            = &max77686_buck_dvs_ops,                       \
+       .type           = REGULATOR_VOLTAGE,                            \
+       .owner          = THIS_MODULE,                                  \
+       .min_uV         = MAX77686_DVS_MINUV,                           \
+       .uV_step        = MAX77686_DVS_UVSTEP,                          \
+       .ramp_delay     = MAX77686_DVS_RAMP_DELAY,                      \
+       .n_voltages     = MAX77686_DVS_VSEL_MASK + 1,                   \
+       .vsel_reg       = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10,      \
+       .vsel_mask      = MAX77686_DVS_VSEL_MASK,                       \
+       .enable_reg     = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10,     \
+       .enable_mask    = MAX77686_OPMODE_MASK                          \
+                       << MAX77686_OPMODE_BUCK234_SHIFT,               \
+}
+
+static struct regulator_desc regulators[] = {
+       regulator_desc_ldo_low(1),
+       regulator_desc_ldo_low(2),
+       regulator_desc_ldo(3),
+       regulator_desc_ldo(4),
+       regulator_desc_ldo(5),
+       regulator_desc_ldo_low(6),
+       regulator_desc_ldo_low(7),
+       regulator_desc_ldo_low(8),
+       regulator_desc_ldo(9),
+       regulator_desc_ldo(10),
+       regulator_desc_ldo(11),
+       regulator_desc_ldo(12),
+       regulator_desc_ldo(13),
+       regulator_desc_ldo(14),
+       regulator_desc_ldo_low(15),
+       regulator_desc_ldo(16),
+       regulator_desc_ldo(17),
+       regulator_desc_ldo(18),
+       regulator_desc_ldo(19),
+       regulator_desc_ldo(20),
+       regulator_desc_ldo(21),
+       regulator_desc_ldo(22),
+       regulator_desc_ldo(23),
+       regulator_desc_ldo(24),
+       regulator_desc_ldo(25),
+       regulator_desc_ldo(26),
+       regulator_desc_buck1(1),
+       regulator_desc_buck_dvs(2),
+       regulator_desc_buck_dvs(3),
+       regulator_desc_buck_dvs(4),
+       regulator_desc_buck(5),
+       regulator_desc_buck(6),
+       regulator_desc_buck(7),
+       regulator_desc_buck(8),
+       regulator_desc_buck(9),
+};
+
+#ifdef CONFIG_OF
+static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+                                       struct max77686_platform_data *pdata)
+{
+       struct device_node *pmic_np, *regulators_np;
+       struct max77686_regulator_data *rdata;
+       struct of_regulator_match rmatch;
+       unsigned int i;
+
+       pmic_np = iodev->dev->of_node;
+       regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
+       if (!regulators_np) {
+               dev_err(iodev->dev, "could not find regulators sub-node\n");
+               return -EINVAL;
+       }
+
+       pdata->num_regulators = ARRAY_SIZE(regulators);
+       rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+                            pdata->num_regulators, GFP_KERNEL);
+       if (!rdata) {
+               dev_err(iodev->dev,
+                       "could not allocate memory for regulator data\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < pdata->num_regulators; i++) {
+               rmatch.name = regulators[i].name;
+               rmatch.init_data = NULL;
+               rmatch.of_node = NULL;
+               of_regulator_match(iodev->dev, regulators_np, &rmatch, 1);
+               rdata[i].initdata = rmatch.init_data;
+       }
+
+       pdata->regulators = rdata;
+
+       return 0;
+}
+#else
+static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+                                       struct max77686_platform_data *pdata)
+{
+       return 0;
+}
+#endif /* CONFIG_OF */
+
+static __devinit int max77686_pmic_probe(struct platform_device *pdev)
+{
+       struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
+       struct regulator_dev **rdev;
+       struct max77686_data *max77686;
+       int i,  size;
+       int ret = 0;
+       struct regulator_config config = { };
+
+       dev_dbg(&pdev->dev, "%s\n", __func__);
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data found for regulator\n");
+               return -ENODEV;
+       }
+
+       if (iodev->dev->of_node) {
+               ret = max77686_pmic_dt_parse_pdata(iodev, pdata);
+               if (ret)
+                       return ret;
+       }
+
+       if (pdata->num_regulators != MAX77686_REGULATORS) {
+               dev_err(&pdev->dev,
+                       "Invalid initial data for regulator's initialiation\n");
+               return -EINVAL;
+       }
+
+       max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data),
+                               GFP_KERNEL);
+       if (!max77686)
+               return -ENOMEM;
+
+       size = sizeof(struct regulator_dev *) * MAX77686_REGULATORS;
+       max77686->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!max77686->rdev)
+               return -ENOMEM;
+
+       rdev = max77686->rdev;
+       config.dev = &pdev->dev;
+       config.regmap = iodev->regmap;
+       platform_set_drvdata(pdev, max77686);
+
+       for (i = 0; i < MAX77686_REGULATORS; i++) {
+               config.init_data = pdata->regulators[i].initdata;
+
+               rdev[i] = regulator_register(&regulators[i], &config);
+               if (IS_ERR(rdev[i])) {
+                       ret = PTR_ERR(rdev[i]);
+                       dev_err(&pdev->dev,
+                               "regulator init failed for %d\n", i);
+                               rdev[i] = NULL;
+                               goto err;
+               }
+       }
+
+       return 0;
+err:
+       while (--i >= 0)
+               regulator_unregister(rdev[i]);
+       return ret;
+}
+
+static int __devexit max77686_pmic_remove(struct platform_device *pdev)
+{
+       struct max77686_data *max77686 = platform_get_drvdata(pdev);
+       struct regulator_dev **rdev = max77686->rdev;
+       int i;
+
+       for (i = 0; i < MAX77686_REGULATORS; i++)
+               if (rdev[i])
+                       regulator_unregister(rdev[i]);
+
+       return 0;
+}
+
+static const struct platform_device_id max77686_pmic_id[] = {
+       {"max77686-pmic", 0},
+       { },
+};
+MODULE_DEVICE_TABLE(platform, max77686_pmic_id);
+
+static struct platform_driver max77686_pmic_driver = {
+       .driver = {
+               .name = "max77686-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = max77686_pmic_probe,
+       .remove = __devexit_p(max77686_pmic_remove),
+       .id_table = max77686_pmic_id,
+};
+
+static int __init max77686_pmic_init(void)
+{
+       return platform_driver_register(&max77686_pmic_driver);
+}
+subsys_initcall(max77686_pmic_init);
+
+static void __exit max77686_pmic_cleanup(void)
+{
+       platform_driver_unregister(&max77686_pmic_driver);
+}
+module_exit(max77686_pmic_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 77686 Regulator Driver");
+MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
+MODULE_LICENSE("GPL");
index 910c9b26d499f45f50034b417790921649fc4a6f..355ca7bad9d59a9583cdda44ee986ced030ab5fa 100644 (file)
@@ -51,7 +51,6 @@ struct max8952_data {
 
        bool vid0;
        bool vid1;
-       bool en;
 };
 
 static int max8952_read_reg(struct max8952_data *max8952, u8 reg)
@@ -80,38 +79,6 @@ static int max8952_list_voltage(struct regulator_dev *rdev,
        return (max8952->pdata->dvs_mode[selector] * 10 + 770) * 1000;
 }
 
-static int max8952_is_enabled(struct regulator_dev *rdev)
-{
-       struct max8952_data *max8952 = rdev_get_drvdata(rdev);
-       return max8952->en;
-}
-
-static int max8952_enable(struct regulator_dev *rdev)
-{
-       struct max8952_data *max8952 = rdev_get_drvdata(rdev);
-
-       /* If not valid, assume "ALWAYS_HIGH" */
-       if (gpio_is_valid(max8952->pdata->gpio_en))
-               gpio_set_value(max8952->pdata->gpio_en, 1);
-
-       max8952->en = true;
-       return 0;
-}
-
-static int max8952_disable(struct regulator_dev *rdev)
-{
-       struct max8952_data *max8952 = rdev_get_drvdata(rdev);
-
-       /* If not valid, assume "ALWAYS_HIGH" -> not permitted */
-       if (gpio_is_valid(max8952->pdata->gpio_en))
-               gpio_set_value(max8952->pdata->gpio_en, 0);
-       else
-               return -EPERM;
-
-       max8952->en = false;
-       return 0;
-}
-
 static int max8952_get_voltage_sel(struct regulator_dev *rdev)
 {
        struct max8952_data *max8952 = rdev_get_drvdata(rdev);
@@ -146,12 +113,8 @@ static int max8952_set_voltage_sel(struct regulator_dev *rdev,
 
 static struct regulator_ops max8952_ops = {
        .list_voltage           = max8952_list_voltage,
-       .is_enabled             = max8952_is_enabled,
-       .enable                 = max8952_enable,
-       .disable                = max8952_disable,
        .get_voltage_sel        = max8952_get_voltage_sel,
        .set_voltage_sel        = max8952_set_voltage_sel,
-       .set_suspend_disable    = max8952_disable,
 };
 
 static const struct regulator_desc regulator = {
@@ -194,6 +157,10 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
        config.init_data = &pdata->reg_data;
        config.driver_data = max8952;
 
+       config.ena_gpio = pdata->gpio_en;
+       if (pdata->reg_data.constraints.boot_on)
+               config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+
        max8952->rdev = regulator_register(&regulator, &config);
 
        if (IS_ERR(max8952->rdev)) {
@@ -202,27 +169,9 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
                return ret;
        }
 
-       max8952->en = !!(pdata->reg_data.constraints.boot_on);
        max8952->vid0 = pdata->default_mode & 0x1;
        max8952->vid1 = (pdata->default_mode >> 1) & 0x1;
 
-       if (gpio_is_valid(pdata->gpio_en)) {
-               if (!gpio_request(pdata->gpio_en, "MAX8952 EN"))
-                       gpio_direction_output(pdata->gpio_en, max8952->en);
-               else
-                       err = 1;
-       } else
-               err = 2;
-
-       if (err) {
-               dev_info(max8952->dev, "EN gpio invalid: assume that EN"
-                               "is always High\n");
-               max8952->en = 1;
-               pdata->gpio_en = -1; /* Mark invalid */
-       }
-
-       err = 0;
-
        if (gpio_is_valid(pdata->gpio_vid0) &&
                        gpio_is_valid(pdata->gpio_vid1)) {
                if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0"))
@@ -308,7 +257,6 @@ static int __devexit max8952_pmic_remove(struct i2c_client *client)
 
        gpio_free(pdata->gpio_vid0);
        gpio_free(pdata->gpio_vid1);
-       gpio_free(pdata->gpio_en);
        return 0;
 }
 
index 704cd49ef3758c9ac00034238838af634e0c27f1..e39a0c7260dca5b7fe13098dbfd06d98c4b0b3e5 100644 (file)
@@ -1025,7 +1025,6 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
         */
        if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
                        pdata->buck5_gpiodvs) {
-               bool gpio1set = false, gpio2set = false;
 
                if (!gpio_is_valid(pdata->buck125_gpios[0]) ||
                                !gpio_is_valid(pdata->buck125_gpios[1]) ||
@@ -1035,40 +1034,20 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
                        goto err_out;
                }
 
-               ret = gpio_request(pdata->buck125_gpios[0],
-                               "MAX8997 SET1");
-               if (ret == -EBUSY)
-                       dev_warn(&pdev->dev, "Duplicated gpio request"
-                                       " on SET1\n");
-               else if (ret)
+               ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[0],
+                                       "MAX8997 SET1");
+               if (ret)
                        goto err_out;
-               else
-                       gpio1set = true;
-
-               ret = gpio_request(pdata->buck125_gpios[1],
-                               "MAX8997 SET2");
-               if (ret == -EBUSY)
-                       dev_warn(&pdev->dev, "Duplicated gpio request"
-                                       " on SET2\n");
-               else if (ret) {
-                       if (gpio1set)
-                               gpio_free(pdata->buck125_gpios[0]);
+
+               ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[1],
+                                       "MAX8997 SET2");
+               if (ret)
                        goto err_out;
-               } else
-                       gpio2set = true;
 
-               ret = gpio_request(pdata->buck125_gpios[2],
+               ret = devm_gpio_request(&pdev->dev, pdata->buck125_gpios[2],
                                "MAX8997 SET3");
-               if (ret == -EBUSY)
-                       dev_warn(&pdev->dev, "Duplicated gpio request"
-                                       " on SET3\n");
-               else if (ret) {
-                       if (gpio1set)
-                               gpio_free(pdata->buck125_gpios[0]);
-                       if (gpio2set)
-                               gpio_free(pdata->buck125_gpios[1]);
+               if (ret)
                        goto err_out;
-               }
 
                gpio_direction_output(pdata->buck125_gpios[0],
                                (max8997->buck125_gpioindex >> 2)
@@ -1079,7 +1058,6 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
                gpio_direction_output(pdata->buck125_gpios[2],
                                (max8997->buck125_gpioindex >> 0)
                                & 0x1); /* SET3 */
-               ret = 0;
        }
 
        /* DVS-GPIO disabled */
index 18bb58b9b96e04836464f86e345310ba1f86227a..5dfa920ff0c8873c91e8c02176af4d722f3c3659 100644 (file)
@@ -111,27 +111,6 @@ static const struct voltage_map_desc *ldo_voltage_map[] = {
        &buck4_voltage_map_desc,        /* BUCK4 */
 };
 
-static int max8998_list_voltage(struct regulator_dev *rdev,
-                               unsigned int selector)
-{
-       const struct voltage_map_desc *desc;
-       int ldo = rdev_get_id(rdev);
-       int val;
-
-       if (ldo >= ARRAY_SIZE(ldo_voltage_map))
-               return -EINVAL;
-
-       desc = ldo_voltage_map[ldo];
-       if (desc == NULL)
-               return -EINVAL;
-
-       val = desc->min + desc->step * selector;
-       if (val > desc->max)
-               return -EINVAL;
-
-       return val * 1000;
-}
-
 static int max8998_get_enable_register(struct regulator_dev *rdev,
                                        int *reg, int *shift)
 {
@@ -297,41 +276,18 @@ static int max8998_get_voltage_sel(struct regulator_dev *rdev)
        return val;
 }
 
-static int max8998_set_voltage_ldo(struct regulator_dev *rdev,
-                                  int min_uV, int max_uV, unsigned *selector)
+static int max8998_set_voltage_ldo_sel(struct regulator_dev *rdev,
+                                      unsigned selector)
 {
        struct max8998_data *max8998 = rdev_get_drvdata(rdev);
        struct i2c_client *i2c = max8998->iodev->i2c;
-       int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
-       const struct voltage_map_desc *desc;
-       int ldo = rdev_get_id(rdev);
-       int reg, shift = 0, mask, ret, i;
-
-       if (ldo >= ARRAY_SIZE(ldo_voltage_map))
-               return -EINVAL;
-
-       desc = ldo_voltage_map[ldo];
-       if (desc == NULL)
-               return -EINVAL;
-
-       if (max_vol < desc->min || min_vol > desc->max)
-               return -EINVAL;
-
-       if (min_vol < desc->min)
-               min_vol = desc->min;
-
-       i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
-
-       if (desc->min + desc->step*i > max_vol)
-               return -EINVAL;
-
-       *selector = i;
+       int reg, shift = 0, mask, ret;
 
        ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
        if (ret)
                return ret;
 
-       ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+       ret = max8998_update_reg(i2c, reg, selector<<shift, mask<<shift);
 
        return ret;
 }
@@ -347,41 +303,18 @@ static inline void buck2_gpio_set(int gpio, int v)
        gpio_set_value(gpio, v & 0x1);
 }
 
-static int max8998_set_voltage_buck(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV, unsigned *selector)
+static int max8998_set_voltage_buck_sel(struct regulator_dev *rdev,
+                                       unsigned selector)
 {
        struct max8998_data *max8998 = rdev_get_drvdata(rdev);
        struct max8998_platform_data *pdata =
                dev_get_platdata(max8998->iodev->dev);
        struct i2c_client *i2c = max8998->iodev->i2c;
-       int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
-       const struct voltage_map_desc *desc;
        int buck = rdev_get_id(rdev);
        int reg, shift = 0, mask, ret;
-       int i, j, previous_sel;
+       int j, previous_sel;
        static u8 buck1_last_val;
 
-       if (buck >= ARRAY_SIZE(ldo_voltage_map))
-               return -EINVAL;
-
-       desc = ldo_voltage_map[buck];
-
-       if (desc == NULL)
-               return -EINVAL;
-
-       if (max_vol < desc->min || min_vol > desc->max)
-               return -EINVAL;
-
-       if (min_vol < desc->min)
-               min_vol = desc->min;
-
-       i = DIV_ROUND_UP(min_vol - desc->min, desc->step);
-
-       if (desc->min + desc->step*i > max_vol)
-               return -EINVAL;
-
-       *selector = i;
-
        ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
        if (ret)
                return ret;
@@ -390,19 +323,19 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
 
        /* Check if voltage needs to be changed */
        /* if previous_voltage equal new voltage, return */
-       if (previous_sel == i) {
+       if (previous_sel == selector) {
                dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n",
-                       max8998_list_voltage(rdev, previous_sel),
-                       max8998_list_voltage(rdev, i));
+                       regulator_list_voltage_linear(rdev, previous_sel),
+                       regulator_list_voltage_linear(rdev, selector));
                return ret;
        }
 
        switch (buck) {
        case MAX8998_BUCK1:
                dev_dbg(max8998->dev,
-                       "BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n"
+                       "BUCK1, selector:%d, buck1_vol1:%d, buck1_vol2:%d\n"
                        "buck1_vol3:%d, buck1_vol4:%d\n",
-                       i, max8998->buck1_vol[0], max8998->buck1_vol[1],
+                       selector, max8998->buck1_vol[0], max8998->buck1_vol[1],
                        max8998->buck1_vol[2], max8998->buck1_vol[3]);
 
                if (gpio_is_valid(pdata->buck1_set1) &&
@@ -411,7 +344,7 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
                        /* check if requested voltage */
                        /* value is already defined */
                        for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) {
-                               if (max8998->buck1_vol[j] == i) {
+                               if (max8998->buck1_vol[j] == selector) {
                                        max8998->buck1_idx = j;
                                        buck1_gpio_set(pdata->buck1_set1,
                                                       pdata->buck1_set2, j);
@@ -426,11 +359,11 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
                        max8998->buck1_idx = (buck1_last_val % 2) + 2;
                        dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
                                max8998->buck1_idx);
-                       max8998->buck1_vol[max8998->buck1_idx] = i;
+                       max8998->buck1_vol[max8998->buck1_idx] = selector;
                        ret = max8998_get_voltage_register(rdev, &reg,
                                                           &shift,
                                                           &mask);
-                       ret = max8998_write_reg(i2c, reg, i);
+                       ret = max8998_write_reg(i2c, reg, selector);
                        buck1_gpio_set(pdata->buck1_set1,
                                       pdata->buck1_set2, max8998->buck1_idx);
                        buck1_last_val++;
@@ -440,20 +373,20 @@ buck1_exit:
                                gpio_get_value(pdata->buck1_set2));
                        break;
                } else {
-                       ret = max8998_write_reg(i2c, reg, i);
+                       ret = max8998_write_reg(i2c, reg, selector);
                }
                break;
 
        case MAX8998_BUCK2:
                dev_dbg(max8998->dev,
-                       "BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
-                       , i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
+                       "BUCK2, selector:%d buck2_vol1:%d, buck2_vol2:%d\n",
+                       selector, max8998->buck2_vol[0], max8998->buck2_vol[1]);
                if (gpio_is_valid(pdata->buck2_set3)) {
 
                        /* check if requested voltage */
                        /* value is already defined */
                        for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
-                               if (max8998->buck2_vol[j] == i) {
+                               if (max8998->buck2_vol[j] == selector) {
                                        max8998->buck2_idx = j;
                                        buck2_gpio_set(pdata->buck2_set3, j);
                                        goto buck2_exit;
@@ -465,20 +398,21 @@ buck1_exit:
 
                        max8998_get_voltage_register(rdev,
                                        &reg, &shift, &mask);
-                       ret = max8998_write_reg(i2c, reg, i);
-                       max8998->buck2_vol[max8998->buck2_idx] = i;
+                       ret = max8998_write_reg(i2c, reg, selector);
+                       max8998->buck2_vol[max8998->buck2_idx] = selector;
                        buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
 buck2_exit:
                        dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
                                gpio_get_value(pdata->buck2_set3));
                } else {
-                       ret = max8998_write_reg(i2c, reg, i);
+                       ret = max8998_write_reg(i2c, reg, selector);
                }
                break;
 
        case MAX8998_BUCK3:
        case MAX8998_BUCK4:
-               ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift);
+               ret = max8998_update_reg(i2c, reg, selector<<shift,
+                                        mask<<shift);
                break;
        }
 
@@ -519,34 +453,30 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops max8998_ldo_ops = {
-       .list_voltage           = max8998_list_voltage,
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = max8998_ldo_is_enabled,
        .enable                 = max8998_ldo_enable,
        .disable                = max8998_ldo_disable,
        .get_voltage_sel        = max8998_get_voltage_sel,
-       .set_voltage            = max8998_set_voltage_ldo,
-       .set_suspend_enable     = max8998_ldo_enable,
-       .set_suspend_disable    = max8998_ldo_disable,
+       .set_voltage_sel        = max8998_set_voltage_ldo_sel,
 };
 
 static struct regulator_ops max8998_buck_ops = {
-       .list_voltage           = max8998_list_voltage,
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
        .is_enabled             = max8998_ldo_is_enabled,
        .enable                 = max8998_ldo_enable,
        .disable                = max8998_ldo_disable,
        .get_voltage_sel        = max8998_get_voltage_sel,
-       .set_voltage            = max8998_set_voltage_buck,
+       .set_voltage_sel        = max8998_set_voltage_buck_sel,
        .set_voltage_time_sel   = max8998_set_voltage_buck_time_sel,
-       .set_suspend_enable     = max8998_ldo_enable,
-       .set_suspend_disable    = max8998_ldo_disable,
 };
 
 static struct regulator_ops max8998_others_ops = {
        .is_enabled             = max8998_ldo_is_enabled,
        .enable                 = max8998_ldo_enable,
        .disable                = max8998_ldo_disable,
-       .set_suspend_enable     = max8998_ldo_enable,
-       .set_suspend_disable    = max8998_ldo_disable,
 };
 
 static struct regulator_desc regulators[] = {
@@ -860,7 +790,10 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
                desc = ldo_voltage_map[id];
                if (desc && regulators[index].ops != &max8998_others_ops) {
                        int count = (desc->max - desc->min) / desc->step + 1;
+
                        regulators[index].n_voltages = count;
+                       regulators[index].min_uV = desc->min * 1000;
+                       regulators[index].uV_step = desc->step * 1000;
                }
 
                config.dev = max8998->dev;
index 7dcdfa283e9368c8bfa492a2104b516dc363d991..4932e3449fe145fc4e27f422df1d1816d7cb99c2 100644 (file)
 
 
 /* Voltage Values */
-static const int mc13783_sw3_val[] = {
+static const unsigned int mc13783_sw3_val[] = {
        5000000, 5000000, 5000000, 5500000,
 };
 
-static const int mc13783_vaudio_val[] = {
+static const unsigned int mc13783_vaudio_val[] = {
        2775000,
 };
 
-static const int mc13783_viohi_val[] = {
+static const unsigned int mc13783_viohi_val[] = {
        2775000,
 };
 
-static const int mc13783_violo_val[] = {
+static const unsigned int mc13783_violo_val[] = {
        1200000, 1300000, 1500000, 1800000,
 };
 
-static const int mc13783_vdig_val[] = {
+static const unsigned int mc13783_vdig_val[] = {
        1200000, 1300000, 1500000, 1800000,
 };
 
-static const int mc13783_vgen_val[] = {
+static const unsigned int mc13783_vgen_val[] = {
        1200000, 1300000, 1500000, 1800000,
        1100000, 2000000, 2775000, 2400000,
 };
 
-static const int mc13783_vrfdig_val[] = {
+static const unsigned int mc13783_vrfdig_val[] = {
        1200000, 1500000, 1800000, 1875000,
 };
 
-static const int mc13783_vrfref_val[] = {
+static const unsigned int mc13783_vrfref_val[] = {
        2475000, 2600000, 2700000, 2775000,
 };
 
-static const int mc13783_vrfcp_val[] = {
+static const unsigned int mc13783_vrfcp_val[] = {
        2700000, 2775000,
 };
 
-static const int mc13783_vsim_val[] = {
+static const unsigned int mc13783_vsim_val[] = {
        1800000, 2900000, 3000000,
 };
 
-static const int mc13783_vesim_val[] = {
+static const unsigned int mc13783_vesim_val[] = {
        1800000, 2900000,
 };
 
-static const int mc13783_vcam_val[] = {
+static const unsigned int mc13783_vcam_val[] = {
        1500000, 1800000, 2500000, 2550000,
        2600000, 2750000, 2800000, 3000000,
 };
 
-static const int mc13783_vrfbg_val[] = {
+static const unsigned int mc13783_vrfbg_val[] = {
        1250000,
 };
 
-static const int mc13783_vvib_val[] = {
+static const unsigned int mc13783_vvib_val[] = {
        1300000, 1800000, 2000000, 3000000,
 };
 
-static const int mc13783_vmmc_val[] = {
+static const unsigned int mc13783_vmmc_val[] = {
        1600000, 1800000, 2000000, 2600000,
        2700000, 2800000, 2900000, 3000000,
 };
 
-static const int mc13783_vrf_val[] = {
+static const unsigned int mc13783_vrf_val[] = {
        1500000, 1875000, 2700000, 2775000,
 };
 
-static const int mc13783_gpo_val[] = {
+static const unsigned int mc13783_gpo_val[] = {
        3100000,
 };
 
-static const int mc13783_pwgtdrv_val[] = {
+static const unsigned int mc13783_pwgtdrv_val[] = {
        5500000,
 };
 
@@ -328,7 +328,7 @@ static struct regulator_ops mc13783_gpo_regulator_ops = {
        .enable = mc13783_gpo_regulator_enable,
        .disable = mc13783_gpo_regulator_disable,
        .is_enabled = mc13783_gpo_regulator_is_enabled,
-       .list_voltage = mc13xxx_regulator_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .set_voltage = mc13xxx_fixed_regulator_set_voltage,
        .get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
index 970a233dbe46f3aa9e167195bc98f0d60ba9d624..b388b746452e024952cbfc6443adb2ec6bc4751b 100644 (file)
 #define MC13892_USB1                           50
 #define MC13892_USB1_VUSBEN                    (1<<3)
 
-static const int mc13892_vcoincell[] = {
+static const unsigned int mc13892_vcoincell[] = {
        2500000, 2700000, 2800000, 2900000, 3000000, 3100000,
        3200000, 3300000,
 };
 
-static const int mc13892_sw1[] = {
+static const unsigned int mc13892_sw1[] = {
        600000,   625000,  650000,  675000,  700000,  725000,
        750000,   775000,  800000,  825000,  850000,  875000,
        900000,   925000,  950000,  975000, 1000000, 1025000,
@@ -164,7 +164,7 @@ static const int mc13892_sw1[] = {
        1350000, 1375000
 };
 
-static const int mc13892_sw[] = {
+static const unsigned int mc13892_sw[] = {
        600000,   625000,  650000,  675000,  700000,  725000,
        750000,   775000,  800000,  825000,  850000,  875000,
        900000,   925000,  950000,  975000, 1000000, 1025000,
@@ -176,65 +176,65 @@ static const int mc13892_sw[] = {
        1800000, 1825000, 1850000, 1875000
 };
 
-static const int mc13892_swbst[] = {
+static const unsigned int mc13892_swbst[] = {
        5000000,
 };
 
-static const int mc13892_viohi[] = {
+static const unsigned int mc13892_viohi[] = {
        2775000,
 };
 
-static const int mc13892_vpll[] = {
+static const unsigned int mc13892_vpll[] = {
        1050000, 1250000, 1650000, 1800000,
 };
 
-static const int mc13892_vdig[] = {
+static const unsigned int mc13892_vdig[] = {
        1050000, 1250000, 1650000, 1800000,
 };
 
-static const int mc13892_vsd[] = {
+static const unsigned int mc13892_vsd[] = {
        1800000, 2000000, 2600000, 2700000,
        2800000, 2900000, 3000000, 3150000,
 };
 
-static const int mc13892_vusb2[] = {
+static const unsigned int mc13892_vusb2[] = {
        2400000, 2600000, 2700000, 2775000,
 };
 
-static const int mc13892_vvideo[] = {
+static const unsigned int mc13892_vvideo[] = {
        2700000, 2775000, 2500000, 2600000,
 };
 
-static const int mc13892_vaudio[] = {
+static const unsigned int mc13892_vaudio[] = {
        2300000, 2500000, 2775000, 3000000,
 };
 
-static const int mc13892_vcam[] = {
+static const unsigned int mc13892_vcam[] = {
        2500000, 2600000, 2750000, 3000000,
 };
 
-static const int mc13892_vgen1[] = {
+static const unsigned int mc13892_vgen1[] = {
        1200000, 1500000, 2775000, 3150000,
 };
 
-static const int mc13892_vgen2[] = {
+static const unsigned int mc13892_vgen2[] = {
        1200000, 1500000, 1600000, 1800000,
        2700000, 2800000, 3000000, 3150000,
 };
 
-static const int mc13892_vgen3[] = {
+static const unsigned int mc13892_vgen3[] = {
        1800000, 2900000,
 };
 
-static const int mc13892_vusb[] = {
+static const unsigned int mc13892_vusb[] = {
        3300000,
 };
 
-static const int mc13892_gpo[] = {
+static const unsigned int mc13892_gpo[] = {
        2750000,
 };
 
-static const int mc13892_pwgtdrv[] = {
+static const unsigned int mc13892_pwgtdrv[] = {
        5000000,
 };
 
@@ -394,7 +394,7 @@ static struct regulator_ops mc13892_gpo_regulator_ops = {
        .enable = mc13892_gpo_regulator_enable,
        .disable = mc13892_gpo_regulator_disable,
        .is_enabled = mc13892_gpo_regulator_is_enabled,
-       .list_voltage = mc13xxx_regulator_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .set_voltage = mc13xxx_fixed_regulator_set_voltage,
        .get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
@@ -436,7 +436,7 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
        u32 valread;
        int ret;
 
-       value = mc13892_regulators[id].voltages[selector];
+       value = rdev->desc->volt_table[selector];
 
        mc13xxx_lock(priv->mc13xxx);
        ret = mc13xxx_reg_read(priv->mc13xxx,
@@ -469,8 +469,7 @@ err:
 }
 
 static struct regulator_ops mc13892_sw_regulator_ops = {
-       .is_enabled = mc13xxx_sw_regulator_is_enabled,
-       .list_voltage = mc13xxx_regulator_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel,
        .get_voltage = mc13892_sw_regulator_get_voltage,
 };
index 4fa9704739bc41bb764ece50e58071783501966a..d6eda28ca5d02dbf4f06498a7787d177304d03f0 100644 (file)
@@ -80,20 +80,6 @@ static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev)
        return (val & mc13xxx_regulators[id].enable_bit) != 0;
 }
 
-int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
-                                               unsigned selector)
-{
-       int id = rdev_get_id(rdev);
-       struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-       struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
-
-       if (selector >= mc13xxx_regulators[id].desc.n_voltages)
-               return -EINVAL;
-
-       return mc13xxx_regulators[id].voltages[selector];
-}
-EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage);
-
 static int mc13xxx_regulator_set_voltage_sel(struct regulator_dev *rdev,
                                             unsigned selector)
 {
@@ -135,14 +121,14 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
 
        BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages);
 
-       return mc13xxx_regulators[id].voltages[val];
+       return rdev->desc->volt_table[val];
 }
 
 struct regulator_ops mc13xxx_regulator_ops = {
        .enable = mc13xxx_regulator_enable,
        .disable = mc13xxx_regulator_disable,
        .is_enabled = mc13xxx_regulator_is_enabled,
-       .list_voltage = mc13xxx_regulator_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .set_voltage_sel = mc13xxx_regulator_set_voltage_sel,
        .get_voltage = mc13xxx_regulator_get_voltage,
 };
@@ -151,15 +137,13 @@ EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops);
 int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
               int max_uV, unsigned *selector)
 {
-       struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-       struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
        int id = rdev_get_id(rdev);
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
                __func__, id, min_uV, max_uV);
 
-       if (min_uV >= mc13xxx_regulators[id].voltages[0] &&
-           max_uV <= mc13xxx_regulators[id].voltages[0])
+       if (min_uV <= rdev->desc->volt_table[0] &&
+           rdev->desc->volt_table[0] <= max_uV)
                return 0;
        else
                return -EINVAL;
@@ -168,13 +152,11 @@ EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage);
 
 int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev)
 {
-       struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-       struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
        int id = rdev_get_id(rdev);
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
 
-       return mc13xxx_regulators[id].voltages[0];
+       return rdev->desc->volt_table[0];
 }
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage);
 
@@ -182,18 +164,12 @@ struct regulator_ops mc13xxx_fixed_regulator_ops = {
        .enable = mc13xxx_regulator_enable,
        .disable = mc13xxx_regulator_disable,
        .is_enabled = mc13xxx_regulator_is_enabled,
-       .list_voltage = mc13xxx_regulator_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .set_voltage = mc13xxx_fixed_regulator_set_voltage,
        .get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
 
-int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev)
-{
-       return 1;
-}
-EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled);
-
 #ifdef CONFIG_OF
 int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
 {
index 044aba4d28eca99f952207adf15e4b382b2c9f96..eaff5510b6df62cc6096c1e6683a4601cdb50240 100644 (file)
@@ -22,7 +22,6 @@ struct mc13xxx_regulator {
        int vsel_shift;
        int vsel_mask;
        int hi_bit;
-       int const *voltages;
 };
 
 struct mc13xxx_regulator_priv {
@@ -33,10 +32,6 @@ struct mc13xxx_regulator_priv {
        struct regulator_dev *regulators[];
 };
 
-extern int mc13xxx_sw_regulator(struct regulator_dev *rdev);
-extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev);
-extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev,
-                                               unsigned selector);
 extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
                int min_uV, int max_uV, unsigned *selector);
 extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev);
@@ -68,6 +63,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
                .desc = {                                               \
                        .name = #_name,                                 \
                        .n_voltages = ARRAY_SIZE(_voltages),            \
+                       .volt_table =  _voltages,                       \
                        .ops = &_ops,                   \
                        .type = REGULATOR_VOLTAGE,                      \
                        .id = prefix ## _name,          \
@@ -78,7 +74,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
                .vsel_reg = prefix ## _vsel_reg,                        \
                .vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\
                .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\
-               .voltages =  _voltages,                                 \
        }
 
 #define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops)     \
@@ -86,6 +81,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
                .desc = {                                               \
                        .name = #_name,                                 \
                        .n_voltages = ARRAY_SIZE(_voltages),            \
+                       .volt_table =  _voltages,                       \
                        .ops = &_ops,           \
                        .type = REGULATOR_VOLTAGE,                      \
                        .id = prefix ## _name,          \
@@ -93,7 +89,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
                },                                                      \
                .reg = prefix ## _reg,                          \
                .enable_bit = prefix ## _reg ## _ ## _name ## EN,       \
-               .voltages =  _voltages,                                 \
        }
 
 #define MC13xxx_GPO_DEFINE(prefix, _name, _reg,  _voltages, _ops)      \
@@ -101,6 +96,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
                .desc = {                                               \
                        .name = #_name,                                 \
                        .n_voltages = ARRAY_SIZE(_voltages),            \
+                       .volt_table =  _voltages,                       \
                        .ops = &_ops,           \
                        .type = REGULATOR_VOLTAGE,                      \
                        .id = prefix ## _name,          \
@@ -108,7 +104,6 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops;
                },                                                      \
                .reg = prefix ## _reg,                          \
                .enable_bit = prefix ## _reg ## _ ## _name ## EN,       \
-               .voltages =  _voltages,                                 \
        }
 
 #define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops)      \
index 56593b75168a28e830946201778cd1937f08a724..3e4106f2bda90ccfa6dc7da80380f314bb5189d8 100644 (file)
@@ -20,7 +20,7 @@ static void of_get_regulation_constraints(struct device_node *np,
                                        struct regulator_init_data **init_data)
 {
        const __be32 *min_uV, *max_uV, *uV_offset;
-       const __be32 *min_uA, *max_uA;
+       const __be32 *min_uA, *max_uA, *ramp_delay;
        struct regulation_constraints *constraints = &(*init_data)->constraints;
 
        constraints->name = of_get_property(np, "regulator-name", NULL);
@@ -60,6 +60,10 @@ static void of_get_regulation_constraints(struct device_node *np,
                constraints->always_on = true;
        else /* status change should be possible if not always on. */
                constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
+
+       ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
+       if (ramp_delay)
+               constraints->ramp_delay = be32_to_cpu(*ramp_delay);
 }
 
 /**
@@ -88,15 +92,17 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
 EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
 
 /**
- * of_regulator_match - extract regulator init data
+ * of_regulator_match - extract regulator init data when node
+ * property "regulator-compatible" matches with the regulator name.
  * @dev: device requesting the data
  * @node: parent device node of the regulators
  * @matches: match table for the regulators
  * @num_matches: number of entries in match table
  *
  * This function uses a match table specified by the regulator driver and
- * looks up the corresponding init data in the device tree. Note that the
- * match table is modified in place.
+ * looks up the corresponding init data in the device tree  if
+ * regulator-compatible matches. Note that the match table is modified
+ * in place.
  *
  * Returns the number of matches found or a negative error code on failure.
  */
@@ -106,27 +112,40 @@ int of_regulator_match(struct device *dev, struct device_node *node,
 {
        unsigned int count = 0;
        unsigned int i;
+       const char *regulator_comp;
+       struct device_node *child;
 
        if (!dev || !node)
                return -EINVAL;
 
-       for (i = 0; i < num_matches; i++) {
-               struct of_regulator_match *match = &matches[i];
-               struct device_node *child;
-
-               child = of_find_node_by_name(node, match->name);
-               if (!child)
-                       continue;
-
-               match->init_data = of_get_regulator_init_data(dev, child);
-               if (!match->init_data) {
-                       dev_err(dev, "failed to parse DT for regulator %s\n",
+       for_each_child_of_node(node, child) {
+               regulator_comp = of_get_property(child,
+                                       "regulator-compatible", NULL);
+               if (!regulator_comp) {
+                       dev_err(dev, "regulator-compatible is missing for node %s\n",
                                child->name);
-                       return -EINVAL;
+                       continue;
+               }
+               for (i = 0; i < num_matches; i++) {
+                       struct of_regulator_match *match = &matches[i];
+                       if (match->of_node)
+                               continue;
+
+                       if (strcmp(match->name, regulator_comp))
+                               continue;
+
+                       match->init_data =
+                               of_get_regulator_init_data(dev, child);
+                       if (!match->init_data) {
+                               dev_err(dev,
+                                       "failed to parse DT for regulator %s\n",
+                                       child->name);
+                               return -EINVAL;
+                       }
+                       match->of_node = child;
+                       count++;
+                       break;
                }
-
-               match->of_node = child;
-               count++;
        }
 
        return count;
index 795f75a6ac3342537a18600e2d0414b1f011caaf..17d19fbbc490156c8507301808863411a5f3135f 100644 (file)
@@ -257,8 +257,7 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
        unsigned int reg;
 
        palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
-       reg &= ~PALMAS_SMPS12_CTRL_STATUS_MASK;
-       reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+       reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
 
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
@@ -374,11 +373,22 @@ static int palmas_set_voltage_smps_sel(struct regulator_dev *dev,
 static int palmas_map_voltage_smps(struct regulator_dev *rdev,
                int min_uV, int max_uV)
 {
+       struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
        int ret, voltage;
 
-       ret = ((min_uV - 500000) / 10000) + 1;
-       if (ret < 0)
-               return ret;
+       if (min_uV == 0)
+               return 0;
+
+       if (pmic->range[id]) { /* RANGE is x2 */
+               if (min_uV < 1000000)
+                       min_uV = 1000000;
+               ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 1;
+       } else {                /* RANGE is x1 */
+               if (min_uV < 500000)
+                       min_uV = 500000;
+               ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 1;
+       }
 
        /* Map back into a voltage to verify we're still in bounds */
        voltage = palmas_list_voltage_smps(rdev, ret);
@@ -400,19 +410,14 @@ static struct regulator_ops palmas_ops_smps = {
        .map_voltage            = palmas_map_voltage_smps,
 };
 
-static int palmas_list_voltage_smps10(struct regulator_dev *dev,
-                                       unsigned selector)
-{
-       return 3750000 + (selector * 1250000);
-}
-
 static struct regulator_ops palmas_ops_smps10 = {
        .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           = palmas_list_voltage_smps10,
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
 };
 
 static int palmas_is_enabled_ldo(struct regulator_dev *dev)
@@ -522,7 +527,15 @@ static int palmas_smps_init(struct palmas *palmas, int id,
        if (ret)
                return ret;
 
-       if (id != PALMAS_REG_SMPS10) {
+       switch (id) {
+       case PALMAS_REG_SMPS10:
+               if (reg_init->mode_sleep) {
+                       reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+                       reg |= reg_init->mode_sleep <<
+                                       PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
+               }
+               break;
+       default:
                if (reg_init->warm_reset)
                        reg |= PALMAS_SMPS12_CTRL_WR_S;
 
@@ -534,14 +547,8 @@ static int palmas_smps_init(struct palmas *palmas, int id,
                        reg |= reg_init->mode_sleep <<
                                        PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT;
                }
-       } else {
-               if (reg_init->mode_sleep) {
-                       reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
-                       reg |= reg_init->mode_sleep <<
-                                       PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
-               }
-
        }
+
        ret = palmas_smps_write(palmas, addr, reg);
        if (ret)
                return ret;
@@ -665,10 +672,8 @@ static __devinit int palmas_probe(struct platform_device *pdev)
                pmic->desc[id].name = palmas_regs_info[id].name;
                pmic->desc[id].id = id;
 
-               if (id != PALMAS_REG_SMPS10) {
-                       pmic->desc[id].ops = &palmas_ops_smps;
-                       pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
-               } else {
+               switch (id) {
+               case PALMAS_REG_SMPS10:
                        pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
                        pmic->desc[id].ops = &palmas_ops_smps10;
                        pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL;
@@ -677,6 +682,12 @@ static __devinit int palmas_probe(struct platform_device *pdev)
                                        PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
                                                        PALMAS_SMPS10_STATUS);
                        pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+                       pmic->desc[id].min_uV = 3750000;
+                       pmic->desc[id].uV_step = 1250000;
+                       break;
+               default:
+                       pmic->desc[id].ops = &palmas_ops_smps;
+                       pmic->desc[id].n_voltages = PALMAS_SMPS_NUM_VOLTAGES;
                }
 
                pmic->desc[id].type = REGULATOR_VOLTAGE;
index 8211101121f0c6a07b68184db5bb95bbd53d7e73..68777acc099fb6da2d0d4f1428b11ef1d704f9a3 100644 (file)
 #include <linux/regulator/machine.h>
 #include <linux/mfd/ezx-pcap.h>
 
-static const u16 V1_table[] = {
-       2775, 1275, 1600, 1725, 1825, 1925, 2075, 2275,
+static const unsigned int V1_table[] = {
+       2775000, 1275000, 1600000, 1725000, 1825000, 1925000, 2075000, 2275000,
 };
 
-static const u16 V2_table[] = {
-       2500, 2775,
+static const unsigned int V2_table[] = {
+       2500000, 2775000,
 };
 
-static const u16 V3_table[] = {
-       1075, 1275, 1550, 1725, 1876, 1950, 2075, 2275,
+static const unsigned int V3_table[] = {
+       1075000, 1275000, 1550000, 1725000, 1876000, 1950000, 2075000, 2275000,
 };
 
-static const u16 V4_table[] = {
-       1275, 1550, 1725, 1875, 1950, 2075, 2275, 2775,
+static const unsigned int V4_table[] = {
+       1275000, 1550000, 1725000, 1875000, 1950000, 2075000, 2275000, 2775000,
 };
 
-static const u16 V5_table[] = {
-       1875, 2275, 2475, 2775,
+static const unsigned int V5_table[] = {
+       1875000, 2275000, 2475000, 2775000,
 };
 
-static const u16 V6_table[] = {
-       2475, 2775,
+static const unsigned int V6_table[] = {
+       2475000, 2775000,
 };
 
-static const u16 V7_table[] = {
-       1875, 2775,
+static const unsigned int V7_table[] = {
+       1875000, 2775000,
 };
 
 #define V8_table V4_table
 
-static const u16 V9_table[] = {
-       1575, 1875, 2475, 2775,
+static const unsigned int V9_table[] = {
+       1575000, 1875000, 2475000, 2775000,
 };
 
-static const u16 V10_table[] = {
-       5000,
+static const unsigned int V10_table[] = {
+       5000000,
 };
 
-static const u16 VAUX1_table[] = {
-       1875, 2475, 2775, 3000,
+static const unsigned int VAUX1_table[] = {
+       1875000, 2475000, 2775000, 3000000,
 };
 
 #define VAUX2_table VAUX1_table
 
-static const u16 VAUX3_table[] = {
-       1200, 1200, 1200, 1200, 1400, 1600, 1800, 2000,
-       2200, 2400, 2600, 2800, 3000, 3200, 3400, 3600,
+static const unsigned int VAUX3_table[] = {
+       1200000, 1200000, 1200000, 1200000, 1400000, 1600000, 1800000, 2000000,
+       2200000, 2400000, 2600000, 2800000, 3000000, 3200000, 3400000, 3600000,
 };
 
-static const u16 VAUX4_table[] = {
-       1800, 1800, 3000, 5000,
+static const unsigned int VAUX4_table[] = {
+       1800000, 1800000, 3000000, 5000000,
 };
 
-static const u16 VSIM_table[] = {
-       1875, 3000,
+static const unsigned int VSIM_table[] = {
+       1875000, 3000000,
 };
 
-static const u16 VSIM2_table[] = {
-       1875,
+static const unsigned int VSIM2_table[] = {
+       1875000,
 };
 
-static const u16 VVIB_table[] = {
-       1300, 1800, 2000, 3000,
+static const unsigned int VVIB_table[] = {
+       1300000, 1800000, 2000000, 3000000,
 };
 
-static const u16 SW1_table[] = {
-       900, 950, 1000, 1050, 1100, 1150, 1200, 1250,
-       1300, 1350, 1400, 1450, 1500, 1600, 1875, 2250,
+static const unsigned int SW1_table[] = {
+        900000,  950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1250000,
+       1300000, 1350000, 1400000, 1450000, 1500000, 1600000, 1875000, 2250000,
 };
 
 #define SW2_table SW1_table
 
-static const u16 SW3_table[] = {
-       4000, 4500, 5000, 5500,
+static const unsigned int SW3_table[] = {
+       4000000, 4500000, 5000000, 5500000,
 };
 
 struct pcap_regulator {
@@ -100,8 +100,6 @@ struct pcap_regulator {
        const u8 index;
        const u8 stby;
        const u8 lowpwr;
-       const u8 n_voltages;
-       const u16 *voltage_table;
 };
 
 #define NA 0xff
@@ -113,8 +111,6 @@ struct pcap_regulator {
                .index          = _index,                               \
                .stby           = _stby,                                \
                .lowpwr         = _lowpwr,                              \
-               .n_voltages     = ARRAY_SIZE(_vreg##_table),            \
-               .voltage_table  = _vreg##_table,                        \
        }
 
 static struct pcap_regulator vreg_table[] = {
@@ -157,11 +153,11 @@ static int pcap_regulator_set_voltage_sel(struct regulator_dev *rdev,
        void *pcap = rdev_get_drvdata(rdev);
 
        /* the regulator doesn't support voltage switching */
-       if (vreg->n_voltages == 1)
+       if (rdev->desc->n_voltages == 1)
                return -EINVAL;
 
        return ezx_pcap_set_bits(pcap, vreg->reg,
-                                (vreg->n_voltages - 1) << vreg->index,
+                                (rdev->desc->n_voltages - 1) << vreg->index,
                                 selector << vreg->index);
 }
 
@@ -171,11 +167,11 @@ static int pcap_regulator_get_voltage_sel(struct regulator_dev *rdev)
        void *pcap = rdev_get_drvdata(rdev);
        u32 tmp;
 
-       if (vreg->n_voltages == 1)
+       if (rdev->desc->n_voltages == 1)
                return 0;
 
        ezx_pcap_read(pcap, vreg->reg, &tmp);
-       tmp = ((tmp >> vreg->index) & (vreg->n_voltages - 1));
+       tmp = ((tmp >> vreg->index) & (rdev->desc->n_voltages - 1));
        return tmp;
 }
 
@@ -214,16 +210,8 @@ static int pcap_regulator_is_enabled(struct regulator_dev *rdev)
        return (tmp >> vreg->en) & 1;
 }
 
-static int pcap_regulator_list_voltage(struct regulator_dev *rdev,
-                                                       unsigned int index)
-{
-       struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)];
-
-       return vreg->voltage_table[index] * 1000;
-}
-
 static struct regulator_ops pcap_regulator_ops = {
-       .list_voltage   = pcap_regulator_list_voltage,
+       .list_voltage   = regulator_list_voltage_table,
        .set_voltage_sel = pcap_regulator_set_voltage_sel,
        .get_voltage_sel = pcap_regulator_get_voltage_sel,
        .enable         = pcap_regulator_enable,
@@ -236,6 +224,7 @@ static struct regulator_ops pcap_regulator_ops = {
                .name           = #_vreg,                       \
                .id             = _vreg,                        \
                .n_voltages     = ARRAY_SIZE(_vreg##_table),    \
+               .volt_table     = _vreg##_table,                \
                .ops            = &pcap_regulator_ops,          \
                .type           = REGULATOR_VOLTAGE,            \
                .owner          = THIS_MODULE,                  \
index 3c9d14c0017bba05c5c770dea4478c51b60f533e..092e5cb848a1e3b0e30736bf6fe08823220f77aa 100644 (file)
@@ -100,13 +100,12 @@ static unsigned int ldo_voltage_value(u8 bits)
        return 900 + (bits * 100);
 }
 
-static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
-                                         int min_uV, int max_uV,
-                                         unsigned *selector)
+static int pcf50633_regulator_map_voltage(struct regulator_dev *rdev,
+                                         int min_uV, int max_uV)
 {
        struct pcf50633 *pcf;
        int regulator_id, millivolts;
-       u8 volt_bits, regnr;
+       u8 volt_bits;
 
        pcf = rdev_get_drvdata(rdev);
 
@@ -116,15 +115,11 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
 
        millivolts = min_uV / 1000;
 
-       regnr = rdev->desc->vsel_reg;
-
        switch (regulator_id) {
        case PCF50633_REGULATOR_AUTO:
                volt_bits = auto_voltage_bits(millivolts);
                break;
        case PCF50633_REGULATOR_DOWN1:
-               volt_bits = down_voltage_bits(millivolts);
-               break;
        case PCF50633_REGULATOR_DOWN2:
                volt_bits = down_voltage_bits(millivolts);
                break;
@@ -142,9 +137,7 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
                return -EINVAL;
        }
 
-       *selector = volt_bits;
-
-       return pcf50633_reg_write(pcf, regnr, volt_bits);
+       return volt_bits;
 }
 
 static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
@@ -159,8 +152,6 @@ static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
                millivolts = auto_voltage_value(index);
                break;
        case PCF50633_REGULATOR_DOWN1:
-               millivolts = down_voltage_value(index);
-               break;
        case PCF50633_REGULATOR_DOWN2:
                millivolts = down_voltage_value(index);
                break;
@@ -182,9 +173,10 @@ static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops pcf50633_regulator_ops = {
-       .set_voltage = pcf50633_regulator_set_voltage,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .list_voltage = pcf50633_regulator_list_voltage,
+       .map_voltage = pcf50633_regulator_map_voltage,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .is_enabled = regulator_is_enabled_regmap,
index 1d34e64a1307ac3b1e6fd9edb0ad47395aee56ef..8bf4e8c9de9a2a811622ff0e8986a8fea9de2735 100644 (file)
@@ -42,7 +42,6 @@ struct rc5t583_regulator_info {
 
        /* Regulator specific turn-on delay  and voltage settling time*/
        int                     enable_uv_per_us;
-       int                     change_uv_per_us;
 
        /* Used by regulator core */
        struct regulator_desc   desc;
@@ -66,25 +65,6 @@ static int rc5t583_regulator_enable_time(struct regulator_dev *rdev)
        return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us);
 }
 
-static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev,
-               unsigned int old_selector, unsigned int new_selector)
-{
-       struct rc5t583_regulator *reg = rdev_get_drvdata(rdev);
-       int old_uV, new_uV;
-       old_uV = regulator_list_voltage_linear(rdev, old_selector);
-
-       if (old_uV < 0)
-               return old_uV;
-
-       new_uV = regulator_list_voltage_linear(rdev, new_selector);
-       if (new_uV < 0)
-               return new_uV;
-
-       return DIV_ROUND_UP(abs(old_uV - new_uV),
-                               reg->reg_info->change_uv_per_us);
-}
-
-
 static struct regulator_ops rc5t583_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
@@ -94,7 +74,7 @@ static struct regulator_ops rc5t583_ops = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
-       .set_voltage_time_sel   = rc5t583_set_voltage_time_sel,
+       .set_voltage_time_sel   = regulator_set_voltage_time_sel,
 };
 
 #define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, \
@@ -104,7 +84,6 @@ static struct regulator_ops rc5t583_ops = {
        .disc_bit       = _disc_bit,                            \
        .deepsleep_reg  = RC5T583_REG_##_id##DAC_DS,            \
        .enable_uv_per_us = _enable_mv * 1000,                  \
-       .change_uv_per_us = 40 * 1000,                          \
        .deepsleep_id   = RC5T583_DS_##_id,                     \
        .desc = {                                               \
                .name = "rc5t583-regulator-"#_id,               \
@@ -119,6 +98,7 @@ static struct regulator_ops rc5t583_ops = {
                .enable_mask = BIT(_en_bit),                    \
                .min_uV = _min_mv * 1000,                       \
                .uV_step = _step_uV,                            \
+               .ramp_delay = 40 * 1000,                        \
        },                                                      \
 }
 
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
new file mode 100644 (file)
index 0000000..4669dc9
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * s2mps11.c
+ *
+ * Copyright (c) 2012 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/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/s2mps11.h>
+
+struct s2mps11_info {
+       struct regulator_dev **rdev;
+
+       int ramp_delay2;
+       int ramp_delay34;
+       int ramp_delay5;
+       int ramp_delay16;
+       int ramp_delay7810;
+       int ramp_delay9;
+
+       bool buck6_ramp;
+       bool buck2_ramp;
+       bool buck3_ramp;
+       bool buck4_ramp;
+};
+
+static int get_ramp_delay(int ramp_delay)
+{
+       unsigned char cnt = 0;
+
+       ramp_delay /= 6;
+
+       while (true) {
+               ramp_delay = ramp_delay >> 1;
+               if (ramp_delay == 0)
+                       break;
+               cnt++;
+       }
+       return cnt;
+}
+
+static struct regulator_ops s2mps11_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 s2mps11_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   = regulator_set_voltage_time_sel,
+};
+
+#define regulator_desc_ldo1(num)       {               \
+       .name           = "LDO"#num,                    \
+       .id             = S2MPS11_LDO##num,             \
+       .ops            = &s2mps11_ldo_ops,             \
+       .type           = REGULATOR_VOLTAGE,            \
+       .owner          = THIS_MODULE,                  \
+       .min_uV         = S2MPS11_LDO_MIN,              \
+       .uV_step        = S2MPS11_LDO_STEP1,            \
+       .n_voltages     = S2MPS11_LDO_N_VOLTAGES,       \
+       .vsel_reg       = S2MPS11_REG_L1CTRL + num - 1, \
+       .vsel_mask      = S2MPS11_LDO_VSEL_MASK,        \
+       .enable_reg     = S2MPS11_REG_L1CTRL + num - 1, \
+       .enable_mask    = S2MPS11_ENABLE_MASK           \
+}
+#define regulator_desc_ldo2(num)       {               \
+       .name           = "LDO"#num,                    \
+       .id             = S2MPS11_LDO##num,             \
+       .ops            = &s2mps11_ldo_ops,             \
+       .type           = REGULATOR_VOLTAGE,            \
+       .owner          = THIS_MODULE,                  \
+       .min_uV         = S2MPS11_LDO_MIN,              \
+       .uV_step        = S2MPS11_LDO_STEP2,            \
+       .n_voltages     = S2MPS11_LDO_N_VOLTAGES,       \
+       .vsel_reg       = S2MPS11_REG_L1CTRL + num - 1, \
+       .vsel_mask      = S2MPS11_LDO_VSEL_MASK,        \
+       .enable_reg     = S2MPS11_REG_L1CTRL + num - 1, \
+       .enable_mask    = S2MPS11_ENABLE_MASK           \
+}
+
+#define regulator_desc_buck1_4(num)    {                       \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPS11_BUCK##num,                    \
+       .ops            = &s2mps11_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPS11_BUCK_MIN1,                    \
+       .uV_step        = S2MPS11_BUCK_STEP1,                   \
+       .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .vsel_reg       = S2MPS11_REG_B1CTRL2 + (num - 1) * 2,  \
+       .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS11_REG_B1CTRL1 + (num - 1) * 2,  \
+       .enable_mask    = S2MPS11_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck5   {                               \
+       .name           = "BUCK5",                              \
+       .id             = S2MPS11_BUCK5,                        \
+       .ops            = &s2mps11_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPS11_BUCK_MIN1,                    \
+       .uV_step        = S2MPS11_BUCK_STEP1,                   \
+       .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .vsel_reg       = S2MPS11_REG_B5CTRL2,                  \
+       .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS11_REG_B5CTRL1,                  \
+       .enable_mask    = S2MPS11_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck6_8(num)    {                       \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPS11_BUCK##num,                    \
+       .ops            = &s2mps11_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPS11_BUCK_MIN1,                    \
+       .uV_step        = S2MPS11_BUCK_STEP1,                   \
+       .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .vsel_reg       = S2MPS11_REG_B6CTRL2 + (num - 6) * 2,  \
+       .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS11_REG_B6CTRL1 + (num - 6) * 2,  \
+       .enable_mask    = S2MPS11_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck9   {                               \
+       .name           = "BUCK9",                              \
+       .id             = S2MPS11_BUCK9,                        \
+       .ops            = &s2mps11_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPS11_BUCK_MIN3,                    \
+       .uV_step        = S2MPS11_BUCK_STEP3,                   \
+       .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .vsel_reg       = S2MPS11_REG_B9CTRL2,                  \
+       .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS11_REG_B9CTRL1,                  \
+       .enable_mask    = S2MPS11_ENABLE_MASK                   \
+}
+
+#define regulator_desc_buck10  {                               \
+       .name           = "BUCK10",                             \
+       .id             = S2MPS11_BUCK10,                       \
+       .ops            = &s2mps11_buck_ops,                    \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = S2MPS11_BUCK_MIN2,                    \
+       .uV_step        = S2MPS11_BUCK_STEP2,                   \
+       .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
+       .vsel_reg       = S2MPS11_REG_B9CTRL2,                  \
+       .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS11_REG_B9CTRL1,                  \
+       .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 __devinit 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 regulator_config config = { };
+       struct regulator_dev **rdev;
+       struct s2mps11_info *s2mps11;
+       int i, ret, size;
+       unsigned char ramp_enable, ramp_reg = 0;
+
+       if (!pdata) {
+               dev_err(pdev->dev.parent, "Platform data not supplied\n");
+               return -ENODEV;
+       }
+
+       s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
+                               GFP_KERNEL);
+       if (!s2mps11)
+               return -ENOMEM;
+
+       size = sizeof(struct regulator_dev *) * S2MPS11_REGULATOR_MAX;
+       s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!s2mps11->rdev) {
+               return -ENOMEM;
+       }
+
+       rdev = s2mps11->rdev;
+       platform_set_drvdata(pdev, s2mps11);
+
+       s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
+       s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
+       s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
+       s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
+       s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
+       s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
+
+       s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
+       s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
+       s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
+       s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
+
+       ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
+               (s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
+
+       if (ramp_enable) {
+               if (s2mps11->buck2_ramp)
+                       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) >> 6;
+               if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
+                       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) >> 4;
+               sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable);
+       }
+
+       ramp_reg &= 0x00;
+       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) >> 6;
+       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) >> 4;
+       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) >> 2;
+       ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
+       sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg);
+
+       for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
+
+               config.dev = &pdev->dev;
+               config.regmap = iodev->regmap;
+               config.init_data = pdata->regulators[i].initdata;
+               config.driver_data = s2mps11;
+
+               rdev[i] = regulator_register(&regulators[i], &config);
+               if (IS_ERR(rdev[i])) {
+                       ret = PTR_ERR(rdev[i]);
+                       dev_err(&pdev->dev, "regulator init failed for %d\n",
+                               i);
+                       rdev[i] = NULL;
+                       goto err;
+               }
+       }
+
+       return 0;
+err:
+       for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
+               if (rdev[i])
+                       regulator_unregister(rdev[i]);
+
+       return ret;
+}
+
+static int __devexit s2mps11_pmic_remove(struct platform_device *pdev)
+{
+       struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev);
+       struct regulator_dev **rdev = s2mps11->rdev;
+       int i;
+
+       for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
+               if (rdev[i])
+                       regulator_unregister(rdev[i]);
+
+       return 0;
+}
+
+static const struct platform_device_id s2mps11_pmic_id[] = {
+       { "s2mps11-pmic", 0},
+       { },
+};
+MODULE_DEVICE_TABLE(platform, s2mps11_pmic_id);
+
+static struct platform_driver s2mps11_pmic_driver = {
+       .driver = {
+               .name = "s2mps11-pmic",
+               .owner = THIS_MODULE,
+       },
+       .probe = s2mps11_pmic_probe,
+       .remove = __devexit_p(s2mps11_pmic_remove),
+       .id_table = s2mps11_pmic_id,
+};
+
+static int __init s2mps11_pmic_init(void)
+{
+       return platform_driver_register(&s2mps11_pmic_driver);
+}
+subsys_initcall(s2mps11_pmic_init);
+
+static void __exit s2mps11_pmic_exit(void)
+{
+       platform_driver_unregister(&s2mps11_pmic_driver);
+}
+module_exit(s2mps11_pmic_exit);
+
+/* Module information */
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("SAMSUNG S2MPS11 Regulator Driver");
+MODULE_LICENSE("GPL");
index 9caadb4821786308aa624e9ef03cd7408dc2083f..102287fa7ecb48df1aae1de76c484b3fe683051d 100644 (file)
@@ -41,6 +41,7 @@ struct s5m8767_info {
        u8 buck3_vol[8];
        u8 buck4_vol[8];
        int buck_gpios[3];
+       int buck_ds[3];
        int buck_gpioindex;
 };
 
@@ -120,27 +121,6 @@ static const struct s5m_voltage_desc *reg_voltage_map[] = {
        [S5M8767_BUCK9] = &buck_voltage_val3,
 };
 
-static int s5m8767_list_voltage(struct regulator_dev *rdev,
-                               unsigned int selector)
-{
-       const struct s5m_voltage_desc *desc;
-       int reg_id = rdev_get_id(rdev);
-       int val;
-
-       if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
-               return -EINVAL;
-
-       desc = reg_voltage_map[reg_id];
-       if (desc == NULL)
-               return -EINVAL;
-
-       val = desc->min + desc->step * selector;
-       if (val > desc->max)
-               return -EINVAL;
-
-       return val;
-}
-
 static unsigned int s5m8767_opmode_reg[][4] = {
        /* {OFF, ON, LOWPOWER, SUSPEND} */
        /* LDO1 ... LDO28 */
@@ -283,17 +263,17 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
                reg = S5M8767_REG_BUCK1CTRL2;
                break;
        case S5M8767_BUCK2:
-               reg = S5M8767_REG_BUCK2DVS1;
+               reg = S5M8767_REG_BUCK2DVS2;
                if (s5m8767->buck2_gpiodvs)
                        reg += s5m8767->buck_gpioindex;
                break;
        case S5M8767_BUCK3:
-               reg = S5M8767_REG_BUCK3DVS1;
+               reg = S5M8767_REG_BUCK3DVS2;
                if (s5m8767->buck3_gpiodvs)
                        reg += s5m8767->buck_gpioindex;
                break;
        case S5M8767_BUCK4:
-               reg = S5M8767_REG_BUCK4DVS1;
+               reg = S5M8767_REG_BUCK4DVS2;
                if (s5m8767->buck4_gpiodvs)
                        reg += s5m8767->buck_gpioindex;
                break;
@@ -357,32 +337,34 @@ static int s5m8767_convert_voltage_to_sel(
        return selector;
 }
 
-static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
+static inline int s5m8767_set_high(struct s5m8767_info *s5m8767)
 {
        int temp_index = s5m8767->buck_gpioindex;
 
        gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
        gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
        gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
+
+       return 0;
 }
 
-static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
+static inline int s5m8767_set_low(struct s5m8767_info *s5m8767)
 {
        int temp_index = s5m8767->buck_gpioindex;
 
        gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
        gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
        gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
+
+       return 0;
 }
 
-static int s5m8767_set_voltage(struct regulator_dev *rdev,
-                               int min_uV, int max_uV, unsigned *selector)
+static int s5m8767_set_voltage_sel(struct regulator_dev *rdev,
+                                  unsigned selector)
 {
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
-       const struct s5m_voltage_desc *desc;
        int reg_id = rdev_get_id(rdev);
-       int sel, reg, mask, ret = 0, old_index, index = 0;
-       u8 val;
+       int reg, mask, ret = 0, old_index, index = 0;
        u8 *buck234_vol = NULL;
 
        switch (reg_id) {
@@ -407,15 +389,9 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev,
                return -EINVAL;
        }
 
-       desc = reg_voltage_map[reg_id];
-
-       sel = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
-       if (sel < 0)
-               return sel;
-
        /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */
        if (buck234_vol) {
-               while (*buck234_vol != sel) {
+               while (*buck234_vol != selector) {
                        buck234_vol++;
                        index++;
                }
@@ -423,22 +399,16 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev,
                s5m8767->buck_gpioindex = index;
 
                if (index > old_index)
-                       s5m8767_set_high(s5m8767);
+                       return s5m8767_set_high(s5m8767);
                else
-                       s5m8767_set_low(s5m8767);
+                       return s5m8767_set_low(s5m8767);
        } else {
                ret = s5m8767_get_voltage_register(rdev, &reg);
                if (ret)
                        return ret;
 
-               s5m_reg_read(s5m8767->iodev, reg, &val);
-               val = (val & ~mask) | sel;
-
-               ret = s5m_reg_write(s5m8767->iodev, reg, val);
+               return s5m_reg_update(s5m8767->iodev, reg, selector, mask);
        }
-
-       *selector = sel;
-       return ret;
 }
 
 static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
@@ -458,15 +428,21 @@ static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops s5m8767_ops = {
-       .list_voltage           = s5m8767_list_voltage,
+       .list_voltage           = regulator_list_voltage_linear,
        .is_enabled             = s5m8767_reg_is_enabled,
        .enable                 = s5m8767_reg_enable,
        .disable                = s5m8767_reg_disable,
        .get_voltage_sel        = s5m8767_get_voltage_sel,
-       .set_voltage            = s5m8767_set_voltage,
+       .set_voltage_sel        = s5m8767_set_voltage_sel,
        .set_voltage_time_sel   = s5m8767_set_voltage_time_sel,
 };
 
+static struct regulator_ops s5m8767_buck78_ops = {
+       .is_enabled             = s5m8767_reg_is_enabled,
+       .enable                 = s5m8767_reg_enable,
+       .disable                = s5m8767_reg_disable,
+};
+
 #define s5m8767_regulator_desc(_name) {                \
        .name           = #_name,               \
        .id             = S5M8767_##_name,      \
@@ -475,6 +451,14 @@ static struct regulator_ops s5m8767_ops = {
        .owner          = THIS_MODULE,          \
 }
 
+#define s5m8767_regulator_buck78_desc(_name) { \
+       .name           = #_name,               \
+       .id             = S5M8767_##_name,      \
+       .ops            = &s5m8767_buck78_ops,  \
+       .type           = REGULATOR_VOLTAGE,    \
+       .owner          = THIS_MODULE,          \
+}
+
 static struct regulator_desc regulators[] = {
        s5m8767_regulator_desc(LDO1),
        s5m8767_regulator_desc(LDO2),
@@ -510,8 +494,8 @@ static struct regulator_desc regulators[] = {
        s5m8767_regulator_desc(BUCK4),
        s5m8767_regulator_desc(BUCK5),
        s5m8767_regulator_desc(BUCK6),
-       s5m8767_regulator_desc(BUCK7),
-       s5m8767_regulator_desc(BUCK8),
+       s5m8767_regulator_buck78_desc(BUCK7),
+       s5m8767_regulator_buck78_desc(BUCK8),
        s5m8767_regulator_desc(BUCK9),
 };
 
@@ -522,7 +506,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
        struct regulator_config config = { };
        struct regulator_dev **rdev;
        struct s5m8767_info *s5m8767;
-       int i, ret, size;
+       int i, ret, size, buck_init;
 
        if (!pdata) {
                dev_err(pdev->dev.parent, "Platform data not supplied\n");
@@ -573,12 +557,37 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
        s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
        s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
        s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
+       s5m8767->buck_ds[0] = pdata->buck_ds[0];
+       s5m8767->buck_ds[1] = pdata->buck_ds[1];
+       s5m8767->buck_ds[2] = pdata->buck_ds[2];
+
        s5m8767->ramp_delay = pdata->buck_ramp_delay;
        s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
        s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
        s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
        s5m8767->opmode = pdata->opmode;
 
+       buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+                                               pdata->buck2_init,
+                                               pdata->buck2_init +
+                                               buck_voltage_val2.step);
+
+       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
+
+       buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+                                               pdata->buck3_init,
+                                               pdata->buck3_init +
+                                               buck_voltage_val2.step);
+
+       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
+
+       buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+                                               pdata->buck4_init,
+                                               pdata->buck4_init +
+                                               buck_voltage_val2.step);
+
+       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
+
        for (i = 0; i < 8; i++) {
                if (s5m8767->buck2_gpiodvs) {
                        s5m8767->buck2_vol[i] =
@@ -608,48 +617,70 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
                }
        }
 
-       if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
-               pdata->buck4_gpiodvs) {
-               if (gpio_is_valid(pdata->buck_gpios[0]) &&
-                       gpio_is_valid(pdata->buck_gpios[1]) &&
-                       gpio_is_valid(pdata->buck_gpios[2])) {
-                       ret = gpio_request(pdata->buck_gpios[0],
-                                               "S5M8767 SET1");
-                       if (ret == -EBUSY)
-                               dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
-
-                       ret = gpio_request(pdata->buck_gpios[1],
-                                          "S5M8767 SET2");
-                       if (ret == -EBUSY)
-                               dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
-
-                       ret = gpio_request(pdata->buck_gpios[2],
-                                          "S5M8767 SET3");
-                       if (ret == -EBUSY)
-                               dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
-                       /* SET1 GPIO */
-                       gpio_direction_output(pdata->buck_gpios[0],
-                                       (s5m8767->buck_gpioindex >> 2) & 0x1);
-                       /* SET2 GPIO */
-                       gpio_direction_output(pdata->buck_gpios[1],
-                                       (s5m8767->buck_gpioindex >> 1) & 0x1);
-                       /* SET3 GPIO */
-                       gpio_direction_output(pdata->buck_gpios[2],
-                                       (s5m8767->buck_gpioindex >> 0) & 0x1);
-                       ret = 0;
-               } else {
-                       dev_err(&pdev->dev, "GPIO NOT VALID\n");
-                       ret = -EINVAL;
+       if (gpio_is_valid(pdata->buck_gpios[0]) &&
+               gpio_is_valid(pdata->buck_gpios[1]) &&
+               gpio_is_valid(pdata->buck_gpios[2])) {
+               ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0],
+                                       "S5M8767 SET1");
+               if (ret)
                        return ret;
-               }
+
+               ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1],
+                                       "S5M8767 SET2");
+               if (ret)
+                       return ret;
+
+               ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2],
+                                       "S5M8767 SET3");
+               if (ret)
+                       return ret;
+
+               /* SET1 GPIO */
+               gpio_direction_output(pdata->buck_gpios[0],
+                               (s5m8767->buck_gpioindex >> 2) & 0x1);
+               /* SET2 GPIO */
+               gpio_direction_output(pdata->buck_gpios[1],
+                               (s5m8767->buck_gpioindex >> 1) & 0x1);
+               /* SET3 GPIO */
+               gpio_direction_output(pdata->buck_gpios[2],
+                               (s5m8767->buck_gpioindex >> 0) & 0x1);
+       } else {
+               dev_err(&pdev->dev, "GPIO NOT VALID\n");
+               ret = -EINVAL;
+               return ret;
        }
 
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
-                       (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
-                       (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
-                       (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
+       ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2");
+       if (ret)
+               return ret;
+
+       ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3");
+       if (ret)
+               return ret;
+
+       ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4");
+       if (ret)
+               return ret;
+
+       /* DS2 GPIO */
+       gpio_direction_output(pdata->buck_ds[0], 0x0);
+       /* DS3 GPIO */
+       gpio_direction_output(pdata->buck_ds[1], 0x0);
+       /* DS4 GPIO */
+       gpio_direction_output(pdata->buck_ds[2], 0x0);
+
+       if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+          pdata->buck4_gpiodvs) {
+               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
+                               (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1),
+                               1 << 1);
+               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
+                               (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1),
+                               1 << 1);
+               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
+                               (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1),
+                               1 << 1);
+       }
 
        /* Initialize GPIO DVS registers */
        for (i = 0; i < 8; i++) {
@@ -668,9 +699,6 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
                                           s5m8767->buck4_vol[i]);
                }
        }
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff);
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff);
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff);
 
        if (s5m8767->buck2_ramp)
                s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
@@ -684,9 +712,13 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
        if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
                || s5m8767->buck4_ramp) {
                switch (s5m8767->ramp_delay) {
-               case 15:
+               case 5:
                        s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
-                                       0xc0, 0xf0);
+                                       0x40, 0xf0);
+                       break;
+               case 10:
+                       s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
+                                       0x90, 0xf0);
                        break;
                case 25:
                        s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
@@ -711,9 +743,12 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
                int id = pdata->regulators[i].id;
 
                desc = reg_voltage_map[id];
-               if (desc)
+               if (desc) {
                        regulators[id].n_voltages =
                                (desc->max - desc->min) / desc->step + 1;
+                       regulators[id].min_uV = desc->min;
+                       regulators[id].uV_step = desc->step;
+               }
 
                config.dev = s5m8767->dev;
                config.init_data = pdata->regulators[i].initdata;
index d840d8440a91691b0954f5cb84fd134c1118f036..1378409efaec70170b8a3c70eeb09e1402abec33 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps6105x.h>
 
-static const int tps6105x_voltages[] = {
+static const unsigned int tps6105x_voltages[] = {
        4500000,
        5000000,
        5250000,
@@ -105,22 +105,13 @@ static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev,
        return 0;
 }
 
-static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev,
-                                          unsigned selector)
-{
-       if (selector >= ARRAY_SIZE(tps6105x_voltages))
-               return -EINVAL;
-
-       return tps6105x_voltages[selector];
-}
-
 static struct regulator_ops tps6105x_regulator_ops = {
        .enable         = tps6105x_regulator_enable,
        .disable        = tps6105x_regulator_disable,
        .is_enabled     = tps6105x_regulator_is_enabled,
        .get_voltage_sel = tps6105x_regulator_get_voltage_sel,
        .set_voltage_sel = tps6105x_regulator_set_voltage_sel,
-       .list_voltage   = tps6105x_regulator_list_voltage,
+       .list_voltage   = regulator_list_voltage_table,
 };
 
 static const struct regulator_desc tps6105x_regulator_desc = {
@@ -130,6 +121,7 @@ static const struct regulator_desc tps6105x_regulator_desc = {
        .id             = 0,
        .owner          = THIS_MODULE,
        .n_voltages     = ARRAY_SIZE(tps6105x_voltages),
+       .volt_table     = tps6105x_voltages,
 };
 
 /*
index e534269ed44aa2afebcd4cc1c7e509354aa92877..68729a7c8709fbcbc8e88e8cf99924afc2e69f18 100644 (file)
@@ -65,10 +65,8 @@ struct tps62360_chip {
        struct regulator_desc desc;
        struct regulator_dev *rdev;
        struct regmap *regmap;
-       int chip_id;
        int vsel0_gpio;
        int vsel1_gpio;
-       int voltage_base;
        u8 voltage_reg_mask;
        bool en_internal_pulldn;
        bool en_discharge;
@@ -76,7 +74,6 @@ struct tps62360_chip {
        int lru_index[4];
        int curr_vset_vsel[4];
        int curr_vset_id;
-       int change_uv_per_us;
 };
 
 /*
@@ -175,23 +172,6 @@ static int tps62360_dcdc_set_voltage_sel(struct regulator_dev *dev,
        return 0;
 }
 
-static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev,
-               unsigned int old_selector, unsigned int new_selector)
-{
-       struct tps62360_chip *tps = rdev_get_drvdata(rdev);
-       int old_uV, new_uV;
-
-       old_uV = regulator_list_voltage_linear(rdev, old_selector);
-       if (old_uV < 0)
-               return old_uV;
-
-       new_uV = regulator_list_voltage_linear(rdev, new_selector);
-       if (new_uV < 0)
-               return new_uV;
-
-       return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us);
-}
-
 static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode)
 {
        struct tps62360_chip *tps = rdev_get_drvdata(rdev);
@@ -258,7 +238,7 @@ static struct regulator_ops tps62360_dcdc_ops = {
        .set_voltage_sel        = tps62360_dcdc_set_voltage_sel,
        .list_voltage           = regulator_list_voltage_linear,
        .map_voltage            = regulator_map_voltage_linear,
-       .set_voltage_time_sel   = tps62360_set_voltage_time_sel,
+       .set_voltage_time_sel   = regulator_set_voltage_time_sel,
        .set_mode               = tps62360_set_mode,
        .get_mode               = tps62360_get_mode,
 };
@@ -301,7 +281,7 @@ static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps,
        ramp_ctrl = (ramp_ctrl >> 4) & 0x7;
 
        /* ramp mV/us = 32/(2^ramp_ctrl) */
-       tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
+       tps->desc.ramp_delay = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
        return ret;
 }
 
@@ -408,13 +388,13 @@ static int __devinit tps62360_probe(struct i2c_client *client,
        switch (chip_id) {
        case TPS62360:
        case TPS62362:
-               tps->voltage_base = TPS62360_BASE_VOLTAGE;
+               tps->desc.min_uV = TPS62360_BASE_VOLTAGE;
                tps->voltage_reg_mask = 0x3F;
                tps->desc.n_voltages = TPS62360_N_VOLTAGES;
                break;
        case TPS62361:
        case TPS62363:
-               tps->voltage_base = TPS62361_BASE_VOLTAGE;
+               tps->desc.min_uV = TPS62361_BASE_VOLTAGE;
                tps->voltage_reg_mask = 0x7F;
                tps->desc.n_voltages = TPS62361_N_VOLTAGES;
                break;
@@ -427,7 +407,6 @@ static int __devinit tps62360_probe(struct i2c_client *client,
        tps->desc.ops = &tps62360_dcdc_ops;
        tps->desc.type = REGULATOR_VOLTAGE;
        tps->desc.owner = THIS_MODULE;
-       tps->desc.min_uV = tps->voltage_base;
        tps->desc.uV_step = 10000;
 
        tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config);
@@ -449,24 +428,24 @@ static int __devinit tps62360_probe(struct i2c_client *client,
                int gpio_flags;
                gpio_flags = (pdata->vsel0_def_state) ?
                                GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-               ret = gpio_request_one(tps->vsel0_gpio,
+               ret = devm_gpio_request_one(&client->dev, tps->vsel0_gpio,
                                gpio_flags, "tps62360-vsel0");
                if (ret) {
                        dev_err(&client->dev,
                                "%s(): Could not obtain vsel0 GPIO %d: %d\n",
                                __func__, tps->vsel0_gpio, ret);
-                       goto err_gpio0;
+                       return ret;
                }
 
                gpio_flags = (pdata->vsel1_def_state) ?
                                GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-               ret = gpio_request_one(tps->vsel1_gpio,
+               ret = devm_gpio_request_one(&client->dev, tps->vsel1_gpio,
                                gpio_flags, "tps62360-vsel1");
                if (ret) {
                        dev_err(&client->dev,
                                "%s(): Could not obtain vsel1 GPIO %d: %d\n",
                                __func__, tps->vsel1_gpio, ret);
-                       goto err_gpio1;
+                       return ret;
                }
                tps->valid_gpios = true;
 
@@ -484,7 +463,7 @@ static int __devinit tps62360_probe(struct i2c_client *client,
        if (ret < 0) {
                dev_err(tps->dev, "%s(): Init failed with err = %d\n",
                                __func__, ret);
-               goto err_init;
+               return ret;
        }
 
        config.dev = &client->dev;
@@ -498,21 +477,11 @@ static int __devinit tps62360_probe(struct i2c_client *client,
                dev_err(tps->dev,
                        "%s(): regulator register failed with err %s\n",
                        __func__, id->name);
-               ret = PTR_ERR(rdev);
-               goto err_init;
+               return PTR_ERR(rdev);
        }
 
        tps->rdev = rdev;
        return 0;
-
-err_init:
-       if (gpio_is_valid(tps->vsel1_gpio))
-               gpio_free(tps->vsel1_gpio);
-err_gpio1:
-       if (gpio_is_valid(tps->vsel0_gpio))
-               gpio_free(tps->vsel0_gpio);
-err_gpio0:
-       return ret;
 }
 
 /**
@@ -525,12 +494,6 @@ static int __devexit tps62360_remove(struct i2c_client *client)
 {
        struct tps62360_chip *tps = i2c_get_clientdata(client);
 
-       if (gpio_is_valid(tps->vsel1_gpio))
-               gpio_free(tps->vsel1_gpio);
-
-       if (gpio_is_valid(tps->vsel0_gpio))
-               gpio_free(tps->vsel0_gpio);
-
        regulator_unregister(tps->rdev);
        return 0;
 }
index 8f1be8586c724a99061092d787273573eda5644e..6998d579d07b424891a79d09e62406a6b7e38d74 100644 (file)
 #define TPS65023_REG_CTRL2_DCDC1       BIT(1)
 #define TPS65023_REG_CTRL2_DCDC3       BIT(0)
 
-/* LDO_CTRL bitfields */
-#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id)   ((ldo_id)*4)
-#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id)    (0x07 << ((ldo_id)*4))
-
 /* Number of step-down converters available */
 #define TPS65023_NUM_DCDC              3
 /* Number of LDO voltage regulators  available */
 #define TPS65023_MAX_REG_ID            TPS65023_LDO_2
 
 /* Supported voltage values for regulators */
-static const u16 VCORE_VSEL_table[] = {
-       800, 825, 850, 875,
-       900, 925, 950, 975,
-       1000, 1025, 1050, 1075,
-       1100, 1125, 1150, 1175,
-       1200, 1225, 1250, 1275,
-       1300, 1325, 1350, 1375,
-       1400, 1425, 1450, 1475,
-       1500, 1525, 1550, 1600,
+static const unsigned int VCORE_VSEL_table[] = {
+       800000, 825000, 850000, 875000,
+       900000, 925000, 950000, 975000,
+       1000000, 1025000, 1050000, 1075000,
+       1100000, 1125000, 1150000, 1175000,
+       1200000, 1225000, 1250000, 1275000,
+       1300000, 1325000, 1350000, 1375000,
+       1400000, 1425000, 1450000, 1475000,
+       1500000, 1525000, 1550000, 1600000,
+};
+
+static const unsigned int DCDC_FIXED_3300000_VSEL_table[] = {
+       3300000,
+};
+
+static const unsigned int DCDC_FIXED_1800000_VSEL_table[] = {
+       1800000,
 };
 
 /* Supported voltage values for LDO regulators for tps65020 */
-static const u16 TPS65020_LDO1_VSEL_table[] = {
-       1000, 1050, 1100, 1300,
-       1800, 2500, 3000, 3300,
+static const unsigned int TPS65020_LDO1_VSEL_table[] = {
+       1000000, 1050000, 1100000, 1300000,
+       1800000, 2500000, 3000000, 3300000,
 };
 
-static const u16 TPS65020_LDO2_VSEL_table[] = {
-       1000, 1050, 1100, 1300,
-       1800, 2500, 3000, 3300,
+static const unsigned int TPS65020_LDO2_VSEL_table[] = {
+       1000000, 1050000, 1100000, 1300000,
+       1800000, 2500000, 3000000, 3300000,
 };
 
 /* Supported voltage values for LDO regulators
  * for tps65021 and tps65023 */
-static const u16 TPS65023_LDO1_VSEL_table[] = {
-       1000, 1100, 1300, 1800,
-       2200, 2600, 2800, 3150,
+static const unsigned int TPS65023_LDO1_VSEL_table[] = {
+       1000000, 1100000, 1300000, 1800000,
+       2200000, 2600000, 2800000, 3150000,
 };
 
-static const u16 TPS65023_LDO2_VSEL_table[] = {
-       1050, 1200, 1300, 1800,
-       2500, 2800, 3000, 3300,
+static const unsigned int TPS65023_LDO2_VSEL_table[] = {
+       1050000, 1200000, 1300000, 1800000,
+       2500000, 2800000, 3000000, 3300000,
 };
 
 /* Regulator specific details */
 struct tps_info {
        const char *name;
-       unsigned min_uV;
-       unsigned max_uV;
-       bool fixed;
        u8 table_len;
-       const u16 *table;
+       const unsigned int *table;
 };
 
 /* PMIC details */
@@ -150,7 +151,7 @@ struct tps_driver_data {
        u8 core_regulator;
 };
 
-static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
+static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
 {
        struct tps_pmic *tps = rdev_get_drvdata(dev);
        int ret;
@@ -164,9 +165,9 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
                if (ret != 0)
                        return ret;
                data &= (tps->info[dcdc]->table_len - 1);
-               return tps->info[dcdc]->table[data] * 1000;
+               return data;
        } else
-               return tps->info[dcdc]->min_uV;
+               return 0;
 }
 
 static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -193,76 +194,14 @@ out:
        return ret;
 }
 
-static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
-{
-       struct tps_pmic *tps = rdev_get_drvdata(dev);
-       int data, ldo = rdev_get_id(dev);
-       int ret;
-
-       if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
-               return -EINVAL;
-
-       ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
-       if (ret != 0)
-               return ret;
-
-       data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
-       data &= (tps->info[ldo]->table_len - 1);
-       return tps->info[ldo]->table[data] * 1000;
-}
-
-static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev,
-                                       unsigned selector)
-{
-       struct tps_pmic *tps = rdev_get_drvdata(dev);
-       int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1;
-
-       return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL,
-                       TPS65023_LDO_CTRL_LDOx_MASK(ldo_index),
-                       selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index));
-}
-
-static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
-                                       unsigned selector)
-{
-       struct tps_pmic *tps = rdev_get_drvdata(dev);
-       int dcdc = rdev_get_id(dev);
-
-       if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
-               return -EINVAL;
-
-       if (dcdc == tps->core_regulator) {
-               if (selector >= tps->info[dcdc]->table_len)
-                       return -EINVAL;
-               else
-                       return tps->info[dcdc]->table[selector] * 1000;
-       } else
-               return tps->info[dcdc]->min_uV;
-}
-
-static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
-                                       unsigned selector)
-{
-       struct tps_pmic *tps = rdev_get_drvdata(dev);
-       int ldo = rdev_get_id(dev);
-
-       if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
-               return -EINVAL;
-
-       if (selector >= tps->info[ldo]->table_len)
-               return -EINVAL;
-       else
-               return tps->info[ldo]->table[selector] * 1000;
-}
-
 /* Operations permitted on VDCDCx */
 static struct regulator_ops tps65023_dcdc_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
-       .get_voltage = tps65023_dcdc_get_voltage,
+       .get_voltage_sel = tps65023_dcdc_get_voltage_sel,
        .set_voltage_sel = tps65023_dcdc_set_voltage_sel,
-       .list_voltage = tps65023_dcdc_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
 };
 
 /* Operations permitted on LDOx */
@@ -270,9 +209,9 @@ static struct regulator_ops tps65023_ldo_ops = {
        .is_enabled = regulator_is_enabled_regmap,
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
-       .get_voltage = tps65023_ldo_get_voltage,
-       .set_voltage_sel = tps65023_ldo_set_voltage_sel,
-       .list_voltage = tps65023_ldo_list_voltage,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .list_voltage = regulator_list_voltage_table,
 };
 
 static struct regmap_config tps65023_regmap_config = {
@@ -325,19 +264,28 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
                tps->desc[i].name = info->name;
                tps->desc[i].id = i;
                tps->desc[i].n_voltages = info->table_len;
+               tps->desc[i].volt_table = info->table;
                tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
                                        &tps65023_ldo_ops : &tps65023_dcdc_ops);
                tps->desc[i].type = REGULATOR_VOLTAGE;
                tps->desc[i].owner = THIS_MODULE;
 
                tps->desc[i].enable_reg = TPS65023_REG_REG_CTRL;
-               if (i == TPS65023_LDO_1)
+               switch (i) {
+               case TPS65023_LDO_1:
+                       tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
+                       tps->desc[i].vsel_mask = 0x07;
                        tps->desc[i].enable_mask = 1 << 1;
-               else if (i == TPS65023_LDO_2)
+                       break;
+               case TPS65023_LDO_2:
+                       tps->desc[i].vsel_reg = TPS65023_REG_LDO_CTRL;
+                       tps->desc[i].vsel_mask = 0x70;
                        tps->desc[i].enable_mask = 1 << 2;
-               else /* DCDCx */
+                       break;
+               default: /* DCDCx */
                        tps->desc[i].enable_mask =
                                        1 << (TPS65023_NUM_REGULATOR - i);
+               }
 
                config.dev = &client->dev;
                config.init_data = init_data;
@@ -384,35 +332,26 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
 static const struct tps_info tps65020_regs[] = {
        {
                .name = "VDCDC1",
-               .min_uV = 3300000,
-               .max_uV = 3300000,
-               .fixed  = 1,
+               .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+               .table = DCDC_FIXED_3300000_VSEL_table,
        },
        {
                .name = "VDCDC2",
-               .min_uV =  1800000,
-               .max_uV = 1800000,
-               .fixed = 1,
+               .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+               .table = DCDC_FIXED_1800000_VSEL_table,
        },
        {
                .name = "VDCDC3",
-               .min_uV =  800000,
-               .max_uV = 1600000,
                .table_len = ARRAY_SIZE(VCORE_VSEL_table),
                .table = VCORE_VSEL_table,
        },
-
        {
                .name = "LDO1",
-               .min_uV = 1000000,
-               .max_uV = 3150000,
                .table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
                .table = TPS65020_LDO1_VSEL_table,
        },
        {
                .name = "LDO2",
-               .min_uV = 1050000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
                .table = TPS65020_LDO2_VSEL_table,
        },
@@ -421,34 +360,26 @@ static const struct tps_info tps65020_regs[] = {
 static const struct tps_info tps65021_regs[] = {
        {
                .name = "VDCDC1",
-               .min_uV =  3300000,
-               .max_uV = 3300000,
-               .fixed = 1,
+               .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+               .table = DCDC_FIXED_3300000_VSEL_table,
        },
        {
                .name = "VDCDC2",
-               .min_uV =  1800000,
-               .max_uV = 1800000,
-               .fixed = 1,
+               .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+               .table = DCDC_FIXED_1800000_VSEL_table,
        },
        {
                .name = "VDCDC3",
-               .min_uV =  800000,
-               .max_uV = 1600000,
                .table_len = ARRAY_SIZE(VCORE_VSEL_table),
                .table = VCORE_VSEL_table,
        },
        {
                .name = "LDO1",
-               .min_uV = 1000000,
-               .max_uV = 3150000,
                .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
                .table = TPS65023_LDO1_VSEL_table,
        },
        {
                .name = "LDO2",
-               .min_uV = 1050000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
                .table = TPS65023_LDO2_VSEL_table,
        },
@@ -457,34 +388,26 @@ static const struct tps_info tps65021_regs[] = {
 static const struct tps_info tps65023_regs[] = {
        {
                .name = "VDCDC1",
-               .min_uV =  800000,
-               .max_uV = 1600000,
                .table_len = ARRAY_SIZE(VCORE_VSEL_table),
                .table = VCORE_VSEL_table,
        },
        {
                .name = "VDCDC2",
-               .min_uV =  3300000,
-               .max_uV = 3300000,
-               .fixed = 1,
+               .table_len = ARRAY_SIZE(DCDC_FIXED_3300000_VSEL_table),
+               .table = DCDC_FIXED_3300000_VSEL_table,
        },
        {
                .name = "VDCDC3",
-               .min_uV =  1800000,
-               .max_uV = 1800000,
-               .fixed = 1,
+               .table_len = ARRAY_SIZE(DCDC_FIXED_1800000_VSEL_table),
+               .table = DCDC_FIXED_1800000_VSEL_table,
        },
        {
                .name = "LDO1",
-               .min_uV = 1000000,
-               .max_uV = 3150000,
                .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
                .table = TPS65023_LDO1_VSEL_table,
        },
        {
                .name = "LDO2",
-               .min_uV = 1050000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
                .table = TPS65023_LDO2_VSEL_table,
        },
index da38be1016aa544b9aeba85975a058018072c4e7..07d01ccdf308fdf2a6871ce60f6d60f380d4060c 100644 (file)
 /* Number of total regulators available */
 #define TPS6507X_NUM_REGULATOR         (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
 
-/* Supported voltage values for regulators (in milliVolts) */
-static const u16 VDCDCx_VSEL_table[] = {
-       725, 750, 775, 800,
-       825, 850, 875, 900,
-       925, 950, 975, 1000,
-       1025, 1050, 1075, 1100,
-       1125, 1150, 1175, 1200,
-       1225, 1250, 1275, 1300,
-       1325, 1350, 1375, 1400,
-       1425, 1450, 1475, 1500,
-       1550, 1600, 1650, 1700,
-       1750, 1800, 1850, 1900,
-       1950, 2000, 2050, 2100,
-       2150, 2200, 2250, 2300,
-       2350, 2400, 2450, 2500,
-       2550, 2600, 2650, 2700,
-       2750, 2800, 2850, 2900,
-       3000, 3100, 3200, 3300,
+/* Supported voltage values for regulators (in microVolts) */
+static const unsigned int VDCDCx_VSEL_table[] = {
+       725000, 750000, 775000, 800000,
+       825000, 850000, 875000, 900000,
+       925000, 950000, 975000, 1000000,
+       1025000, 1050000, 1075000, 1100000,
+       1125000, 1150000, 1175000, 1200000,
+       1225000, 1250000, 1275000, 1300000,
+       1325000, 1350000, 1375000, 1400000,
+       1425000, 1450000, 1475000, 1500000,
+       1550000, 1600000, 1650000, 1700000,
+       1750000, 1800000, 1850000, 1900000,
+       1950000, 2000000, 2050000, 2100000,
+       2150000, 2200000, 2250000, 2300000,
+       2350000, 2400000, 2450000, 2500000,
+       2550000, 2600000, 2650000, 2700000,
+       2750000, 2800000, 2850000, 2900000,
+       3000000, 3100000, 3200000, 3300000,
 };
 
-static const u16 LDO1_VSEL_table[] = {
-       1000, 1100, 1200, 1250,
-       1300, 1350, 1400, 1500,
-       1600, 1800, 2500, 2750,
-       2800, 3000, 3100, 3300,
+static const unsigned int LDO1_VSEL_table[] = {
+       1000000, 1100000, 1200000, 1250000,
+       1300000, 1350000, 1400000, 1500000,
+       1600000, 1800000, 2500000, 2750000,
+       2800000, 3000000, 3100000, 3300000,
 };
 
-static const u16 LDO2_VSEL_table[] = {
-       725, 750, 775, 800,
-       825, 850, 875, 900,
-       925, 950, 975, 1000,
-       1025, 1050, 1075, 1100,
-       1125, 1150, 1175, 1200,
-       1225, 1250, 1275, 1300,
-       1325, 1350, 1375, 1400,
-       1425, 1450, 1475, 1500,
-       1550, 1600, 1650, 1700,
-       1750, 1800, 1850, 1900,
-       1950, 2000, 2050, 2100,
-       2150, 2200, 2250, 2300,
-       2350, 2400, 2450, 2500,
-       2550, 2600, 2650, 2700,
-       2750, 2800, 2850, 2900,
-       3000, 3100, 3200, 3300,
-};
+/* The voltage mapping table for LDO2 is the same as VDCDCx */
+#define LDO2_VSEL_table VDCDCx_VSEL_table
 
 struct tps_info {
        const char *name;
-       unsigned min_uV;
-       unsigned max_uV;
        u8 table_len;
-       const u16 *table;
+       const unsigned int *table;
 
        /* Does DCDC high or the low register defines output voltage? */
        bool defdcdc_default;
@@ -103,36 +85,26 @@ struct tps_info {
 static struct tps_info tps6507x_pmic_regs[] = {
        {
                .name = "VDCDC1",
-               .min_uV = 725000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
                .table = VDCDCx_VSEL_table,
        },
        {
                .name = "VDCDC2",
-               .min_uV = 725000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
                .table = VDCDCx_VSEL_table,
        },
        {
                .name = "VDCDC3",
-               .min_uV = 725000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
                .table = VDCDCx_VSEL_table,
        },
        {
                .name = "LDO1",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(LDO1_VSEL_table),
                .table = LDO1_VSEL_table,
        },
        {
                .name = "LDO2",
-               .min_uV = 725000,
-               .max_uV = 3300000,
                .table_len = ARRAY_SIZE(LDO2_VSEL_table),
                .table = LDO2_VSEL_table,
        },
@@ -375,28 +347,13 @@ static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
        return tps6507x_pmic_reg_write(tps, reg, data);
 }
 
-static int tps6507x_pmic_list_voltage(struct regulator_dev *dev,
-                                       unsigned selector)
-{
-       struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
-       int rid = rdev_get_id(dev);
-
-       if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
-               return -EINVAL;
-
-       if (selector >= tps->info[rid]->table_len)
-               return -EINVAL;
-       else
-               return tps->info[rid]->table[selector] * 1000;
-}
-
 static struct regulator_ops tps6507x_pmic_ops = {
        .is_enabled = tps6507x_pmic_is_enabled,
        .enable = tps6507x_pmic_enable,
        .disable = tps6507x_pmic_disable,
        .get_voltage_sel = tps6507x_pmic_get_voltage_sel,
        .set_voltage_sel = tps6507x_pmic_set_voltage_sel,
-       .list_voltage = tps6507x_pmic_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
 };
 
 static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
@@ -449,6 +406,7 @@ static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
                tps->desc[i].name = info->name;
                tps->desc[i].id = i;
                tps->desc[i].n_voltages = info->table_len;
+               tps->desc[i].volt_table = info->table;
                tps->desc[i].ops = &tps6507x_pmic_ops;
                tps->desc[i].type = REGULATOR_VOLTAGE;
                tps->desc[i].owner = THIS_MODULE;
index 9d371d2cbcae9a5f62e7484260f2879c341905bc..6caa222af77a284f09f1e8a5f634da794dd84838 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps65217.h>
 
-#define TPS65217_REGULATOR(_name, _id, _ops, _n)       \
+#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t) \
        {                                               \
                .name           = _name,                \
                .id             = _id,                  \
                .n_voltages     = _n,                   \
                .type           = REGULATOR_VOLTAGE,    \
                .owner          = THIS_MODULE,          \
+               .vsel_reg       = _vr,                  \
+               .vsel_mask      = _vm,                  \
+               .enable_reg     = TPS65217_REG_ENABLE,  \
+               .enable_mask    = _em,                  \
+               .volt_table     = _t,                   \
        }                                               \
 
-#define TPS65217_INFO(_nm, _min, _max, _f1, _f2, _t, _n, _em, _vr, _vm)        \
+#define TPS65217_INFO(_nm, _min, _max, _f1, _f2)       \
        {                                               \
                .name           = _nm,                  \
                .min_uV         = _min,                 \
                .max_uV         = _max,                 \
                .vsel_to_uv     = _f1,                  \
                .uv_to_vsel     = _f2,                  \
-               .table          = _t,                   \
-               .table_len      = _n,                   \
-               .enable_mask    = _em,                  \
-               .set_vout_reg   = _vr,                  \
-               .set_vout_mask  = _vm,                  \
        }
 
-static const int LDO1_VSEL_table[] = {
+static const unsigned int LDO1_VSEL_table[] = {
        1000000, 1100000, 1200000, 1250000,
        1300000, 1350000, 1400000, 1500000,
        1600000, 1800000, 2500000, 2750000,
@@ -78,7 +78,7 @@ static int tps65217_vsel_to_uv1(unsigned int vsel)
 
 static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel)
 {
-       if ((uV < 0) && (uV > 3300000))
+       if (uV < 0 || uV > 3300000)
                return -EINVAL;
 
        if (uV <= 1500000)
@@ -112,7 +112,7 @@ static int tps65217_vsel_to_uv2(unsigned int vsel)
 
 static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
 {
-       if ((uV < 0) && (uV > 3300000))
+       if (uV < 0 || uV > 3300000)
                return -EINVAL;
 
        if (uV <= 1900000)
@@ -127,46 +127,20 @@ static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
 
 static struct tps_info tps65217_pmic_regs[] = {
        TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1,
-                       tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC1_EN,
-                       TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK),
+                       tps65217_uv_to_vsel1),
        TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1,
-                       tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC2_EN,
-                       TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK),
+                       tps65217_uv_to_vsel1),
        TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1,
-                       tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_DC3_EN,
-                       TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK),
-       TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL, LDO1_VSEL_table,
-                       16, TPS65217_ENABLE_LDO1_EN, TPS65217_REG_DEFLDO1,
-                       TPS65217_DEFLDO1_LDO1_MASK),
+                       tps65217_uv_to_vsel1),
+       TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL),
        TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1,
-                       tps65217_uv_to_vsel1, NULL, 64, TPS65217_ENABLE_LDO2_EN,
-                       TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK),
+                       tps65217_uv_to_vsel1),
        TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2,
-                       tps65217_uv_to_vsel2, NULL, 32,
-                       TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
-                       TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK),
+                       tps65217_uv_to_vsel2),
        TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2,
-                       tps65217_uv_to_vsel2, NULL, 32,
-                       TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
-                       TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK),
+                       tps65217_uv_to_vsel2),
 };
 
-static int tps65217_pmic_is_enabled(struct regulator_dev *dev)
-{
-       int ret;
-       struct tps65217 *tps = rdev_get_drvdata(dev);
-       unsigned int data, rid = rdev_get_id(dev);
-
-       if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
-               return -EINVAL;
-
-       ret = tps65217_reg_read(tps, TPS65217_REG_ENABLE, &data);
-       if (ret)
-               return ret;
-
-       return (data & tps->info[rid]->enable_mask) ? 1 : 0;
-}
-
 static int tps65217_pmic_enable(struct regulator_dev *dev)
 {
        struct tps65217 *tps = rdev_get_drvdata(dev);
@@ -177,9 +151,8 @@ static int tps65217_pmic_enable(struct regulator_dev *dev)
 
        /* Enable the regulator and password protection is level 1 */
        return tps65217_set_bits(tps, TPS65217_REG_ENABLE,
-                               tps->info[rid]->enable_mask,
-                               tps->info[rid]->enable_mask,
-                               TPS65217_PROTECT_L1);
+                                dev->desc->enable_mask, dev->desc->enable_mask,
+                                TPS65217_PROTECT_L1);
 }
 
 static int tps65217_pmic_disable(struct regulator_dev *dev)
@@ -192,25 +165,7 @@ static int tps65217_pmic_disable(struct regulator_dev *dev)
 
        /* Disable the regulator and password protection is level 1 */
        return tps65217_clear_bits(tps, TPS65217_REG_ENABLE,
-                       tps->info[rid]->enable_mask, TPS65217_PROTECT_L1);
-}
-
-static int tps65217_pmic_get_voltage_sel(struct regulator_dev *dev)
-{
-       int ret;
-       struct tps65217 *tps = rdev_get_drvdata(dev);
-       unsigned int selector, rid = rdev_get_id(dev);
-
-       if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
-               return -EINVAL;
-
-       ret = tps65217_reg_read(tps, tps->info[rid]->set_vout_reg, &selector);
-       if (ret)
-               return ret;
-
-       selector &= tps->info[rid]->set_vout_mask;
-
-       return selector;
+                                  dev->desc->enable_mask, TPS65217_PROTECT_L1);
 }
 
 static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
@@ -221,8 +176,7 @@ static int tps65217_pmic_set_voltage_sel(struct regulator_dev *dev,
        unsigned int rid = rdev_get_id(dev);
 
        /* Set the voltage based on vsel value and write protect level is 2 */
-       ret = tps65217_set_bits(tps, tps->info[rid]->set_vout_reg,
-                               tps->info[rid]->set_vout_mask,
+       ret = tps65217_set_bits(tps, dev->desc->vsel_reg, dev->desc->vsel_mask,
                                selector, TPS65217_PROTECT_L2);
 
        /* Set GO bit for DCDCx to initiate voltage transistion */
@@ -252,10 +206,10 @@ static int tps65217_pmic_map_voltage(struct regulator_dev *dev,
        if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
                return -EINVAL;
 
-       if (min_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
-               return -EINVAL;
+       if (min_uV < tps->info[rid]->min_uV)
+               min_uV = tps->info[rid]->min_uV;
 
-       if (max_uV < tps->info[rid]->min_uV || max_uV > tps->info[rid]->max_uV)
+       if (max_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
                return -EINVAL;
 
        ret = tps->info[rid]->uv_to_vsel(min_uV, &sel);
@@ -274,21 +228,18 @@ static int tps65217_pmic_list_voltage(struct regulator_dev *dev,
        if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
                return -EINVAL;
 
-       if (selector >= tps->info[rid]->table_len)
+       if (selector >= dev->desc->n_voltages)
                return -EINVAL;
 
-       if (tps->info[rid]->table)
-               return tps->info[rid]->table[selector];
-
        return tps->info[rid]->vsel_to_uv(selector);
 }
 
 /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
 static struct regulator_ops tps65217_pmic_ops = {
-       .is_enabled             = tps65217_pmic_is_enabled,
+       .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = tps65217_pmic_enable,
        .disable                = tps65217_pmic_disable,
-       .get_voltage_sel        = tps65217_pmic_get_voltage_sel,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = tps65217_pmic_set_voltage_sel,
        .list_voltage           = tps65217_pmic_list_voltage,
        .map_voltage            = tps65217_pmic_map_voltage,
@@ -296,22 +247,38 @@ static struct regulator_ops tps65217_pmic_ops = {
 
 /* Operations permitted on LDO1 */
 static struct regulator_ops tps65217_pmic_ldo1_ops = {
-       .is_enabled             = tps65217_pmic_is_enabled,
+       .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = tps65217_pmic_enable,
        .disable                = tps65217_pmic_disable,
-       .get_voltage_sel        = tps65217_pmic_get_voltage_sel,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
        .set_voltage_sel        = tps65217_pmic_set_voltage_sel,
-       .list_voltage           = tps65217_pmic_list_voltage,
+       .list_voltage           = regulator_list_voltage_table,
 };
 
 static const struct regulator_desc regulators[] = {
-       TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64),
-       TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64),
-       TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64),
-       TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16),
-       TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64),
-       TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32),
-       TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32),
+       TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64,
+                          TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK,
+                          TPS65217_ENABLE_DC1_EN, NULL),
+       TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64,
+                          TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK,
+                          TPS65217_ENABLE_DC2_EN, NULL),
+       TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64,
+                          TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK,
+                          TPS65217_ENABLE_DC3_EN, NULL),
+       TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16,
+                          TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK,
+                          TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table),
+       TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64,
+                          TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK,
+                          TPS65217_ENABLE_LDO2_EN, NULL),
+       TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32,
+                          TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
+                          TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
+                          NULL),
+       TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32,
+                          TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
+                          TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
+                          NULL),
 };
 
 static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
@@ -326,6 +293,7 @@ static int __devinit tps65217_regulator_probe(struct platform_device *pdev)
        tps->info[pdev->id] = info;
 
        config.dev = &pdev->dev;
+       config.of_node = pdev->dev.of_node;
        config.init_data = pdev->dev.platform_data;
        config.driver_data = tps;
 
index 1b299aacf22ffa2023652c5a45cf61ac1a1c1416..947ece933d901fa75ef54e286979d12f02dea7ce 100644 (file)
 #define N_SWITCH               2
 #define N_REGULATORS           (N_DCDC + N_LDO + N_SWITCH)
 
-#define FIXED_ILIMSEL          BIT(0)
-#define FIXED_VOLTAGE          BIT(1)
-
 #define CMD_READ(reg)          ((reg) << 6)
 #define CMD_WRITE(reg)         (BIT(5) | (reg) << 6)
 #define STAT_CLK               BIT(3)
@@ -129,12 +126,9 @@ struct field {
 struct supply_info {
        const char      *name;
        int             n_voltages;
-       const int       *voltages;
-       int             fixed_voltage;
+       const unsigned int *voltages;
        int             n_ilimsels;
-       const int       *ilimsels;
-       int             fixed_ilimsel;
-       int             flags;
+       const unsigned int *ilimsels;
        struct field    enable, voltage, ilimsel;
 };
 
@@ -307,7 +301,7 @@ static int write_field(struct tps6524x *hw, const struct field *field,
                                    val << field->shift);
 }
 
-static const int dcdc1_voltages[] = {
+static const unsigned int dcdc1_voltages[] = {
         800000,  825000,  850000,  875000,
         900000,  925000,  950000,  975000,
        1000000, 1025000, 1050000, 1075000,
@@ -318,7 +312,7 @@ static const int dcdc1_voltages[] = {
        1500000, 1525000, 1550000, 1575000,
 };
 
-static const int dcdc2_voltages[] = {
+static const unsigned int dcdc2_voltages[] = {
        1400000, 1450000, 1500000, 1550000,
        1600000, 1650000, 1700000, 1750000,
        1800000, 1850000, 1900000, 1950000,
@@ -329,7 +323,7 @@ static const int dcdc2_voltages[] = {
        2800000, 2850000, 2900000, 2950000,
 };
 
-static const int dcdc3_voltages[] = {
+static const unsigned int dcdc3_voltages[] = {
        2400000, 2450000, 2500000, 2550000, 2600000,
        2650000, 2700000, 2750000, 2800000, 2850000,
        2900000, 2950000, 3000000, 3050000, 3100000,
@@ -337,38 +331,54 @@ static const int dcdc3_voltages[] = {
        3400000, 3450000, 3500000, 3550000, 3600000,
 };
 
-static const int ldo1_voltages[] = {
+static const unsigned int ldo1_voltages[] = {
        4300000, 4350000, 4400000, 4450000,
        4500000, 4550000, 4600000, 4650000,
        4700000, 4750000, 4800000, 4850000,
        4900000, 4950000, 5000000, 5050000,
 };
 
-static const int ldo2_voltages[] = {
+static const unsigned int ldo2_voltages[] = {
        1100000, 1150000, 1200000, 1250000,
        1300000, 1700000, 1750000, 1800000,
        1850000, 1900000, 3150000, 3200000,
        3250000, 3300000, 3350000, 3400000,
 };
 
-static const int ldo_ilimsel[] = {
+static const unsigned int fixed_5000000_voltage[] = {
+       5000000
+};
+
+static const unsigned int ldo_ilimsel[] = {
        400000, 1500000
 };
 
-static const int usb_ilimsel[] = {
+static const unsigned int usb_ilimsel[] = {
        200000, 400000, 800000, 1000000
 };
 
+static const unsigned int fixed_2400000_ilimsel[] = {
+       2400000
+};
+
+static const unsigned int fixed_1200000_ilimsel[] = {
+       1200000
+};
+
+static const unsigned int fixed_400000_ilimsel[] = {
+       400000
+};
+
 #define __MK_FIELD(_reg, _mask, _shift) \
        { .reg = (_reg), .mask = (_mask), .shift = (_shift), }
 
 static const struct supply_info supply_info[N_REGULATORS] = {
        {
                .name           = "DCDC1",
-               .flags          = FIXED_ILIMSEL,
                .n_voltages     = ARRAY_SIZE(dcdc1_voltages),
                .voltages       = dcdc1_voltages,
-               .fixed_ilimsel  = 2400000,
+               .n_ilimsels     = ARRAY_SIZE(fixed_2400000_ilimsel),
+               .ilimsels       = fixed_2400000_ilimsel,
                .enable         = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
                                             DCDCDCDC1_EN_SHIFT),
                .voltage        = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
@@ -376,10 +386,10 @@ static const struct supply_info supply_info[N_REGULATORS] = {
        },
        {
                .name           = "DCDC2",
-               .flags          = FIXED_ILIMSEL,
                .n_voltages     = ARRAY_SIZE(dcdc2_voltages),
                .voltages       = dcdc2_voltages,
-               .fixed_ilimsel  = 1200000,
+               .n_ilimsels     = ARRAY_SIZE(fixed_1200000_ilimsel),
+               .ilimsels       = fixed_1200000_ilimsel,
                .enable         = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
                                             DCDCDCDC2_EN_SHIFT),
                .voltage        = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
@@ -387,10 +397,10 @@ static const struct supply_info supply_info[N_REGULATORS] = {
        },
        {
                .name           = "DCDC3",
-               .flags          = FIXED_ILIMSEL,
                .n_voltages     = ARRAY_SIZE(dcdc3_voltages),
                .voltages       = dcdc3_voltages,
-               .fixed_ilimsel  = 1200000,
+               .n_ilimsels     = ARRAY_SIZE(fixed_1200000_ilimsel),
+               .ilimsels       = fixed_1200000_ilimsel,
                .enable         = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK,
                                        DCDCDCDC3_EN_SHIFT),
                .voltage        = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK,
@@ -424,8 +434,8 @@ static const struct supply_info supply_info[N_REGULATORS] = {
        },
        {
                .name           = "USB",
-               .flags          = FIXED_VOLTAGE,
-               .fixed_voltage  = 5000000,
+               .n_voltages     = ARRAY_SIZE(fixed_5000000_voltage),
+               .voltages       = fixed_5000000_voltage,
                .n_ilimsels     = ARRAY_SIZE(usb_ilimsel),
                .ilimsels       = usb_ilimsel,
                .enable         = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
@@ -435,29 +445,15 @@ static const struct supply_info supply_info[N_REGULATORS] = {
        },
        {
                .name           = "LCD",
-               .flags          = FIXED_VOLTAGE | FIXED_ILIMSEL,
-               .fixed_voltage  = 5000000,
-               .fixed_ilimsel  =  400000,
+               .n_voltages     = ARRAY_SIZE(fixed_5000000_voltage),
+               .voltages       = fixed_5000000_voltage,
+               .n_ilimsels     = ARRAY_SIZE(fixed_400000_ilimsel),
+               .ilimsels       = fixed_400000_ilimsel,
                .enable         = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK,
                                             BLOCK_LCD_SHIFT),
        },
 };
 
-static int list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
-       const struct supply_info *info;
-       struct tps6524x *hw;
-
-       hw      = rdev_get_drvdata(rdev);
-       info    = &supply_info[rdev_get_id(rdev)];
-
-       if (info->flags & FIXED_VOLTAGE)
-               return selector ? -EINVAL : info->fixed_voltage;
-
-       return ((selector < info->n_voltages) ?
-               info->voltages[selector] : -EINVAL);
-}
-
 static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
 {
        const struct supply_info *info;
@@ -466,7 +462,7 @@ static int set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
        hw      = rdev_get_drvdata(rdev);
        info    = &supply_info[rdev_get_id(rdev)];
 
-       if (info->flags & FIXED_VOLTAGE)
+       if (rdev->desc->n_voltages == 1)
                return -EINVAL;
 
        return write_field(hw, &info->voltage, selector);
@@ -481,7 +477,7 @@ static int get_voltage_sel(struct regulator_dev *rdev)
        hw      = rdev_get_drvdata(rdev);
        info    = &supply_info[rdev_get_id(rdev)];
 
-       if (info->flags & FIXED_VOLTAGE)
+       if (rdev->desc->n_voltages == 1)
                return 0;
 
        ret = read_field(hw, &info->voltage);
@@ -503,7 +499,7 @@ static int set_current_limit(struct regulator_dev *rdev, int min_uA,
        hw      = rdev_get_drvdata(rdev);
        info    = &supply_info[rdev_get_id(rdev)];
 
-       if (info->flags & FIXED_ILIMSEL)
+       if (info->n_ilimsels == 1)
                return -EINVAL;
 
        for (i = 0; i < info->n_ilimsels; i++)
@@ -526,8 +522,8 @@ static int get_current_limit(struct regulator_dev *rdev)
        hw      = rdev_get_drvdata(rdev);
        info    = &supply_info[rdev_get_id(rdev)];
 
-       if (info->flags & FIXED_ILIMSEL)
-               return info->fixed_ilimsel;
+       if (info->n_ilimsels == 1)
+               return info->ilimsels[0];
 
        ret = read_field(hw, &info->ilimsel);
        if (ret < 0)
@@ -577,7 +573,7 @@ static struct regulator_ops regulator_ops = {
        .disable                = disable_supply,
        .get_voltage_sel        = get_voltage_sel,
        .set_voltage_sel        = set_voltage_sel,
-       .list_voltage           = list_voltage,
+       .list_voltage           = regulator_list_voltage_table,
        .set_current_limit      = set_current_limit,
        .get_current_limit      = get_current_limit,
 };
@@ -629,13 +625,11 @@ static int __devinit pmic_probe(struct spi_device *spi)
                hw->desc[i].name        = info->name;
                hw->desc[i].id          = i;
                hw->desc[i].n_voltages  = info->n_voltages;
+               hw->desc[i].volt_table  = info->voltages;
                hw->desc[i].ops         = &regulator_ops;
                hw->desc[i].type        = REGULATOR_VOLTAGE;
                hw->desc[i].owner       = THIS_MODULE;
 
-               if (info->flags & FIXED_VOLTAGE)
-                       hw->desc[i].n_voltages = 1;
-
                config.dev = dev;
                config.init_data = init_data;
                config.driver_data = hw;
index c0a214575380020473f593f43beb8c34bbe7fed5..e6da90ab5153dedd64ebd96137776f652af7d152 100644 (file)
@@ -63,8 +63,6 @@ struct tps6586x_regulator {
        int enable_bit[2];
        int enable_reg[2];
 
-       int *voltages;
-
        /* for DVM regulators */
        int go_reg;
        int go_bit;
@@ -72,22 +70,9 @@ struct tps6586x_regulator {
 
 static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
 {
-       return rdev_get_dev(rdev)->parent->parent;
+       return rdev_get_dev(rdev)->parent;
 }
 
-static int tps6586x_list_voltage(struct regulator_dev *rdev, unsigned selector)
-{
-       struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
-       int rid = rdev_get_id(rdev);
-
-       /* LDO0 has minimal voltage 1.2V rather than 1.25V */
-       if ((rid == TPS6586X_ID_LDO_0) && (selector == 0))
-               return (info->voltages[0] - 50) * 1000;
-
-       return info->voltages[selector] * 1000;
-}
-
-
 static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
                                    unsigned selector)
 {
@@ -168,7 +153,7 @@ static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
 }
 
 static struct regulator_ops tps6586x_regulator_ops = {
-       .list_voltage = tps6586x_list_voltage,
+       .list_voltage = regulator_list_voltage_table,
        .get_voltage_sel = tps6586x_get_voltage_sel,
        .set_voltage_sel = tps6586x_set_voltage_sel,
 
@@ -177,39 +162,45 @@ static struct regulator_ops tps6586x_regulator_ops = {
        .disable = tps6586x_regulator_disable,
 };
 
-static int tps6586x_ldo_voltages[] = {
-       1250, 1500, 1800, 2500, 2700, 2850, 3100, 3300,
+static const unsigned int tps6586x_ldo0_voltages[] = {
+       1200000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
+};
+
+static const unsigned int tps6586x_ldo4_voltages[] = {
+       1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000,
+       1900000, 1925000, 1950000, 1975000, 2000000, 2025000, 2050000, 2075000,
+       2100000, 2125000, 2150000, 2175000, 2200000, 2225000, 2250000, 2275000,
+       2300000, 2325000, 2350000, 2375000, 2400000, 2425000, 2450000, 2475000,
 };
 
-static int tps6586x_ldo4_voltages[] = {
-       1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
-       1900, 1925, 1950, 1975, 2000, 2025, 2050, 2075,
-       2100, 2125, 2150, 2175, 2200, 2225, 2250, 2275,
-       2300, 2325, 2350, 2375, 2400, 2425, 2450, 2475,
+static const unsigned int tps6586x_ldo_voltages[] = {
+       1250000, 1500000, 1800000, 2500000, 2700000, 2850000, 3100000, 3300000,
 };
 
-static int tps6586x_sm2_voltages[] = {
-       3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350,
-       3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750,
-       3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150,
-       4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550,
+static const unsigned int tps6586x_sm2_voltages[] = {
+       3000000, 3050000, 3100000, 3150000, 3200000, 3250000, 3300000, 3350000,
+       3400000, 3450000, 3500000, 3550000, 3600000, 3650000, 3700000, 3750000,
+       3800000, 3850000, 3900000, 3950000, 4000000, 4050000, 4100000, 4150000,
+       4200000, 4250000, 4300000, 4350000, 4400000, 4450000, 4500000, 4550000,
 };
 
-static int tps6586x_dvm_voltages[] = {
-        725,  750,  775,  800,  825,  850,  875,  900,
-        925,  950,  975, 1000, 1025, 1050, 1075, 1100,
-       1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
-       1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+static const unsigned int tps6586x_dvm_voltages[] = {
+        725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
+        925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
+       1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
+       1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
 };
 
-#define TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits,             \
+#define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits,  \
                           ereg0, ebit0, ereg1, ebit1)                  \
        .desc   = {                                                     \
+               .supply_name = _pin_name,                               \
                .name   = "REG-" #_id,                                  \
                .ops    = &tps6586x_regulator_ops,                      \
                .type   = REGULATOR_VOLTAGE,                            \
                .id     = TPS6586X_ID_##_id,                            \
                .n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages),  \
+               .volt_table = tps6586x_##vdata##_voltages,              \
                .owner  = THIS_MODULE,                                  \
        },                                                              \
        .volt_reg       = TPS6586X_##vreg,                              \
@@ -218,44 +209,45 @@ static int tps6586x_dvm_voltages[] = {
        .enable_reg[0]  = TPS6586X_SUPPLY##ereg0,                       \
        .enable_bit[0]  = (ebit0),                                      \
        .enable_reg[1]  = TPS6586X_SUPPLY##ereg1,                       \
-       .enable_bit[1]  = (ebit1),                                      \
-       .voltages       = tps6586x_##vdata##_voltages,
+       .enable_bit[1]  = (ebit1),
 
 #define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)                     \
        .go_reg = TPS6586X_##goreg,                                     \
        .go_bit = (gobit),
 
-#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits,                   \
+#define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits,           \
                     ereg0, ebit0, ereg1, ebit1)                        \
 {                                                                      \
-       TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits,              \
+       TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,      \
                           ereg0, ebit0, ereg1, ebit1)                  \
 }
 
-#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits,                   \
+#define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits,           \
                     ereg0, ebit0, ereg1, ebit1, goreg, gobit)          \
 {                                                                      \
-       TPS6586X_REGULATOR(_id, vdata, vreg, shift, nbits,              \
+       TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits,      \
                           ereg0, ebit0, ereg1, ebit1)                  \
        TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)                      \
 }
 
 static struct tps6586x_regulator tps6586x_regulator[] = {
-       TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
-       TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
-       TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
-       TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
-       TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
-       TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
-       TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
-       TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
-       TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
-       TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
-
-       TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6),
-       TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6),
-       TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
-       TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
+       TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0),
+       TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
+       TPS6586X_LDO(LDO_5, NULL, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
+       TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
+       TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
+       TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
+       TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
+       TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
+       TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
+       TPS6586X_LDO(SM_2, "sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
+
+       TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
+                                       ENB, 3, VCC2, 6),
+       TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
+                                       END, 3, VCC1, 6),
+       TPS6586X_DVM(SM_0, "sm0", dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
+       TPS6586X_DVM(SM_1, "sm1", dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
 };
 
 /*
@@ -362,7 +354,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       config.dev = &pdev->dev;
+       config.dev = pdev->dev.parent;
        config.of_node = pdev->dev.of_node;
        config.init_data = pdev->dev.platform_data;
        config.driver_data = ri;
index 6bf864b4bdf67e8ddd860ed16fe0e7248e65318b..793adda560c3c3364c2053cdb152974fc2a2f02b 100644 (file)
                        TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 |          \
                        TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
 
-/* supported VIO voltages in millivolts */
-static const u16 VIO_VSEL_table[] = {
-       1500, 1800, 2500, 3300,
+/* supported VIO voltages in microvolts */
+static const unsigned int VIO_VSEL_table[] = {
+       1500000, 1800000, 2500000, 3300000,
 };
 
 /* VSEL tables for TPS65910 specific LDOs and dcdc's */
 
-/* supported VDD3 voltages in millivolts */
-static const u16 VDD3_VSEL_table[] = {
-       5000,
+/* supported VDD3 voltages in microvolts */
+static const unsigned int VDD3_VSEL_table[] = {
+       5000000,
 };
 
-/* supported VDIG1 voltages in millivolts */
-static const u16 VDIG1_VSEL_table[] = {
-       1200, 1500, 1800, 2700,
+/* supported VDIG1 voltages in microvolts */
+static const unsigned int VDIG1_VSEL_table[] = {
+       1200000, 1500000, 1800000, 2700000,
 };
 
-/* supported VDIG2 voltages in millivolts */
-static const u16 VDIG2_VSEL_table[] = {
-       1000, 1100, 1200, 1800,
+/* supported VDIG2 voltages in microvolts */
+static const unsigned int VDIG2_VSEL_table[] = {
+       1000000, 1100000, 1200000, 1800000,
 };
 
-/* supported VPLL voltages in millivolts */
-static const u16 VPLL_VSEL_table[] = {
-       1000, 1100, 1800, 2500,
+/* supported VPLL voltages in microvolts */
+static const unsigned int VPLL_VSEL_table[] = {
+       1000000, 1100000, 1800000, 2500000,
 };
 
-/* supported VDAC voltages in millivolts */
-static const u16 VDAC_VSEL_table[] = {
-       1800, 2600, 2800, 2850,
+/* supported VDAC voltages in microvolts */
+static const unsigned int VDAC_VSEL_table[] = {
+       1800000, 2600000, 2800000, 2850000,
 };
 
-/* supported VAUX1 voltages in millivolts */
-static const u16 VAUX1_VSEL_table[] = {
-       1800, 2500, 2800, 2850,
+/* supported VAUX1 voltages in microvolts */
+static const unsigned int VAUX1_VSEL_table[] = {
+       1800000, 2500000, 2800000, 2850000,
 };
 
-/* supported VAUX2 voltages in millivolts */
-static const u16 VAUX2_VSEL_table[] = {
-       1800, 2800, 2900, 3300,
+/* supported VAUX2 voltages in microvolts */
+static const unsigned int VAUX2_VSEL_table[] = {
+       1800000, 2800000, 2900000, 3300000,
 };
 
-/* supported VAUX33 voltages in millivolts */
-static const u16 VAUX33_VSEL_table[] = {
-       1800, 2000, 2800, 3300,
+/* supported VAUX33 voltages in microvolts */
+static const unsigned int VAUX33_VSEL_table[] = {
+       1800000, 2000000, 2800000, 3300000,
 };
 
-/* supported VMMC voltages in millivolts */
-static const u16 VMMC_VSEL_table[] = {
-       1800, 2800, 3000, 3300,
+/* supported VMMC voltages in microvolts */
+static const unsigned int VMMC_VSEL_table[] = {
+       1800000, 2800000, 3000000, 3300000,
 };
 
 struct tps_info {
        const char *name;
-       unsigned min_uV;
-       unsigned max_uV;
+       const char *vin_name;
        u8 n_voltages;
-       const u16 *voltage_table;
+       const unsigned int *voltage_table;
        int enable_time_us;
 };
 
 static struct tps_info tps65910_regs[] = {
        {
                .name = "vrtc",
+               .vin_name = "vcc7",
                .enable_time_us = 2200,
        },
        {
                .name = "vio",
-               .min_uV = 1500000,
-               .max_uV = 3300000,
+               .vin_name = "vccio",
                .n_voltages = ARRAY_SIZE(VIO_VSEL_table),
                .voltage_table = VIO_VSEL_table,
                .enable_time_us = 350,
        },
        {
                .name = "vdd1",
-               .min_uV = 600000,
-               .max_uV = 4500000,
+               .vin_name = "vcc1",
                .enable_time_us = 350,
        },
        {
                .name = "vdd2",
-               .min_uV = 600000,
-               .max_uV = 4500000,
+               .vin_name = "vcc2",
                .enable_time_us = 350,
        },
        {
                .name = "vdd3",
-               .min_uV = 5000000,
-               .max_uV = 5000000,
                .n_voltages = ARRAY_SIZE(VDD3_VSEL_table),
                .voltage_table = VDD3_VSEL_table,
                .enable_time_us = 200,
        },
        {
                .name = "vdig1",
-               .min_uV = 1200000,
-               .max_uV = 2700000,
+               .vin_name = "vcc6",
                .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table),
                .voltage_table = VDIG1_VSEL_table,
                .enable_time_us = 100,
        },
        {
                .name = "vdig2",
-               .min_uV = 1000000,
-               .max_uV = 1800000,
+               .vin_name = "vcc6",
                .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table),
                .voltage_table = VDIG2_VSEL_table,
                .enable_time_us = 100,
        },
        {
                .name = "vpll",
-               .min_uV = 1000000,
-               .max_uV = 2500000,
+               .vin_name = "vcc5",
                .n_voltages = ARRAY_SIZE(VPLL_VSEL_table),
                .voltage_table = VPLL_VSEL_table,
                .enable_time_us = 100,
        },
        {
                .name = "vdac",
-               .min_uV = 1800000,
-               .max_uV = 2850000,
+               .vin_name = "vcc5",
                .n_voltages = ARRAY_SIZE(VDAC_VSEL_table),
                .voltage_table = VDAC_VSEL_table,
                .enable_time_us = 100,
        },
        {
                .name = "vaux1",
-               .min_uV = 1800000,
-               .max_uV = 2850000,
+               .vin_name = "vcc4",
                .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table),
                .voltage_table = VAUX1_VSEL_table,
                .enable_time_us = 100,
        },
        {
                .name = "vaux2",
-               .min_uV = 1800000,
-               .max_uV = 3300000,
+               .vin_name = "vcc4",
                .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table),
                .voltage_table = VAUX2_VSEL_table,
                .enable_time_us = 100,
        },
        {
                .name = "vaux33",
-               .min_uV = 1800000,
-               .max_uV = 3300000,
+               .vin_name = "vcc3",
                .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table),
                .voltage_table = VAUX33_VSEL_table,
                .enable_time_us = 100,
        },
        {
                .name = "vmmc",
-               .min_uV = 1800000,
-               .max_uV = 3300000,
+               .vin_name = "vcc3",
                .n_voltages = ARRAY_SIZE(VMMC_VSEL_table),
                .voltage_table = VMMC_VSEL_table,
                .enable_time_us = 100,
@@ -194,91 +181,79 @@ static struct tps_info tps65910_regs[] = {
 static struct tps_info tps65911_regs[] = {
        {
                .name = "vrtc",
+               .vin_name = "vcc7",
                .enable_time_us = 2200,
        },
        {
                .name = "vio",
-               .min_uV = 1500000,
-               .max_uV = 3300000,
+               .vin_name = "vccio",
                .n_voltages = ARRAY_SIZE(VIO_VSEL_table),
                .voltage_table = VIO_VSEL_table,
                .enable_time_us = 350,
        },
        {
                .name = "vdd1",
-               .min_uV = 600000,
-               .max_uV = 4500000,
-               .n_voltages = 73,
+               .vin_name = "vcc1",
+               .n_voltages = 0x4C,
                .enable_time_us = 350,
        },
        {
                .name = "vdd2",
-               .min_uV = 600000,
-               .max_uV = 4500000,
-               .n_voltages = 73,
+               .vin_name = "vcc2",
+               .n_voltages = 0x4C,
                .enable_time_us = 350,
        },
        {
                .name = "vddctrl",
-               .min_uV = 600000,
-               .max_uV = 1400000,
-               .n_voltages = 65,
+               .n_voltages = 0x44,
                .enable_time_us = 900,
        },
        {
                .name = "ldo1",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 47,
+               .vin_name = "vcc6",
+               .n_voltages = 0x33,
                .enable_time_us = 420,
        },
        {
                .name = "ldo2",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 47,
+               .vin_name = "vcc6",
+               .n_voltages = 0x33,
                .enable_time_us = 420,
        },
        {
                .name = "ldo3",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 24,
+               .vin_name = "vcc5",
+               .n_voltages = 0x1A,
                .enable_time_us = 230,
        },
        {
                .name = "ldo4",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 47,
+               .vin_name = "vcc5",
+               .n_voltages = 0x33,
                .enable_time_us = 230,
        },
        {
                .name = "ldo5",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 24,
+               .vin_name = "vcc4",
+               .n_voltages = 0x1A,
                .enable_time_us = 230,
        },
        {
                .name = "ldo6",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 24,
+               .vin_name = "vcc3",
+               .n_voltages = 0x1A,
                .enable_time_us = 230,
        },
        {
                .name = "ldo7",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 24,
+               .vin_name = "vcc3",
+               .n_voltages = 0x1A,
                .enable_time_us = 230,
        },
        {
                .name = "ldo8",
-               .min_uV = 1000000,
-               .max_uV = 3300000,
-               .n_voltages = 24,
+               .vin_name = "vcc3",
+               .n_voltages = 0x1A,
                .enable_time_us = 230,
        },
 };
@@ -321,7 +296,6 @@ struct tps65910_reg {
        struct tps65910 *mfd;
        struct regulator_dev **rdev;
        struct tps_info **info;
-       struct mutex mutex;
        int num_regulators;
        int mode;
        int  (*get_ctrl_reg)(int);
@@ -329,71 +303,6 @@ struct tps65910_reg {
        unsigned int board_ext_control[TPS65910_NUM_REGS];
 };
 
-static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
-{
-       unsigned int val;
-       int err;
-
-       err = tps65910_reg_read(pmic->mfd, reg, &val);
-       if (err)
-               return err;
-
-       return val;
-}
-
-static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg,
-                                       u8 set_mask, u8 clear_mask)
-{
-       int err, data;
-
-       mutex_lock(&pmic->mutex);
-
-       data = tps65910_read(pmic, reg);
-       if (data < 0) {
-               dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
-               err = data;
-               goto out;
-       }
-
-       data &= ~clear_mask;
-       data |= set_mask;
-       err = tps65910_reg_write(pmic->mfd, reg, data);
-       if (err)
-               dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
-
-out:
-       mutex_unlock(&pmic->mutex);
-       return err;
-}
-
-static int tps65910_reg_read_locked(struct tps65910_reg *pmic, u8 reg)
-{
-       int data;
-
-       mutex_lock(&pmic->mutex);
-
-       data = tps65910_read(pmic, reg);
-       if (data < 0)
-               dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
-
-       mutex_unlock(&pmic->mutex);
-       return data;
-}
-
-static int tps65910_reg_write_locked(struct tps65910_reg *pmic, u8 reg, u8 val)
-{
-       int err;
-
-       mutex_lock(&pmic->mutex);
-
-       err = tps65910_reg_write(pmic->mfd, reg, val);
-       if (err < 0)
-               dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
-
-       mutex_unlock(&pmic->mutex);
-       return err;
-}
-
 static int tps65910_get_ctrl_register(int id)
 {
        switch (id) {
@@ -462,13 +371,6 @@ static int tps65911_get_ctrl_register(int id)
        }
 }
 
-static int tps65910_enable_time(struct regulator_dev *dev)
-{
-       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-       int id = rdev_get_id(dev);
-       return pmic->info[id]->enable_time_us;
-}
-
 static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
@@ -481,8 +383,9 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
 
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
-               return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT,
-                                                       LDO_ST_MODE_BIT);
+               return tps65910_reg_update_bits(pmic->mfd, reg,
+                                               LDO_ST_MODE_BIT | LDO_ST_ON_BIT,
+                                               LDO_ST_ON_BIT);
        case REGULATOR_MODE_IDLE:
                value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT;
                return tps65910_reg_set_bits(mfd, reg, value);
@@ -496,15 +399,15 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
 static unsigned int tps65910_get_mode(struct regulator_dev *dev)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-       int reg, value, id = rdev_get_id(dev);
+       int ret, reg, value, id = rdev_get_id(dev);
 
        reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
-       value = tps65910_reg_read_locked(pmic, reg);
-       if (value < 0)
-               return value;
+       ret = tps65910_reg_read(pmic->mfd, reg, &value);
+       if (ret < 0)
+               return ret;
 
        if (!(value & LDO_ST_ON_BIT))
                return REGULATOR_MODE_STANDBY;
@@ -517,33 +420,51 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev)
 static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-       int id = rdev_get_id(dev);
+       int ret, id = rdev_get_id(dev);
        int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
 
        switch (id) {
        case TPS65910_REG_VDD1:
-               opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_OP);
-               mult = tps65910_reg_read_locked(pmic, TPS65910_VDD1);
+               ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1_OP, &opvsel);
+               if (ret < 0)
+                       return ret;
+               ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1, &mult);
+               if (ret < 0)
+                       return ret;
                mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
-               srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_SR);
+               ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD1_SR, &srvsel);
+               if (ret < 0)
+                       return ret;
                sr = opvsel & VDD1_OP_CMD_MASK;
                opvsel &= VDD1_OP_SEL_MASK;
                srvsel &= VDD1_SR_SEL_MASK;
                vselmax = 75;
                break;
        case TPS65910_REG_VDD2:
-               opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_OP);
-               mult = tps65910_reg_read_locked(pmic, TPS65910_VDD2);
+               ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2_OP, &opvsel);
+               if (ret < 0)
+                       return ret;
+               ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2, &mult);
+               if (ret < 0)
+                       return ret;
                mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
-               srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_SR);
+               ret = tps65910_reg_read(pmic->mfd, TPS65910_VDD2_SR, &srvsel);
+               if (ret < 0)
+                       return ret;
                sr = opvsel & VDD2_OP_CMD_MASK;
                opvsel &= VDD2_OP_SEL_MASK;
                srvsel &= VDD2_SR_SEL_MASK;
                vselmax = 75;
                break;
        case TPS65911_REG_VDDCTRL:
-               opvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_OP);
-               srvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_SR);
+               ret = tps65910_reg_read(pmic->mfd, TPS65911_VDDCTRL_OP,
+                                       &opvsel);
+               if (ret < 0)
+                       return ret;
+               ret = tps65910_reg_read(pmic->mfd, TPS65911_VDDCTRL_SR,
+                                       &srvsel);
+               if (ret < 0)
+                       return ret;
                sr = opvsel & VDDCTRL_OP_CMD_MASK;
                opvsel &= VDDCTRL_OP_SEL_MASK;
                srvsel &= VDDCTRL_SR_SEL_MASK;
@@ -577,15 +498,15 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)
 static int tps65910_get_voltage_sel(struct regulator_dev *dev)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-       int reg, value, id = rdev_get_id(dev);
+       int ret, reg, value, id = rdev_get_id(dev);
 
        reg = pmic->get_ctrl_reg(id);
        if (reg < 0)
                return reg;
 
-       value = tps65910_reg_read_locked(pmic, reg);
-       if (value < 0)
-               return value;
+       ret = tps65910_reg_read(pmic->mfd, reg, &value);
+       if (ret < 0)
+               return ret;
 
        switch (id) {
        case TPS65910_REG_VIO:
@@ -609,18 +530,20 @@ static int tps65910_get_voltage_sel(struct regulator_dev *dev)
 
 static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
 {
-       return 5 * 1000 * 1000;
+       return dev->desc->volt_table[0];
 }
 
 static int tps65911_get_voltage_sel(struct regulator_dev *dev)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-       int id = rdev_get_id(dev);
-       u8 value, reg;
+       int ret, id = rdev_get_id(dev);
+       unsigned int value, reg;
 
        reg = pmic->get_ctrl_reg(id);
 
-       value = tps65910_reg_read_locked(pmic, reg);
+       ret = tps65910_reg_read(pmic->mfd, reg, &value);
+       if (ret < 0)
+               return ret;
 
        switch (id) {
        case TPS65911_REG_LDO1:
@@ -662,10 +585,10 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev,
                        dcdc_mult--;
                vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
 
-               tps65910_modify_bits(pmic, TPS65910_VDD1,
-                               (dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
-                                               VDD1_VGAIN_SEL_MASK);
-               tps65910_reg_write_locked(pmic, TPS65910_VDD1_OP, vsel);
+               tps65910_reg_update_bits(pmic->mfd, TPS65910_VDD1,
+                                        VDD1_VGAIN_SEL_MASK,
+                                        dcdc_mult << VDD1_VGAIN_SEL_SHIFT);
+               tps65910_reg_write(pmic->mfd, TPS65910_VDD1_OP, vsel);
                break;
        case TPS65910_REG_VDD2:
                dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
@@ -673,14 +596,14 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev,
                        dcdc_mult--;
                vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
 
-               tps65910_modify_bits(pmic, TPS65910_VDD2,
-                               (dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
-                                               VDD1_VGAIN_SEL_MASK);
-               tps65910_reg_write_locked(pmic, TPS65910_VDD2_OP, vsel);
+               tps65910_reg_update_bits(pmic->mfd, TPS65910_VDD2,
+                                        VDD1_VGAIN_SEL_MASK,
+                                        dcdc_mult << VDD2_VGAIN_SEL_SHIFT);
+               tps65910_reg_write(pmic->mfd, TPS65910_VDD2_OP, vsel);
                break;
        case TPS65911_REG_VDDCTRL:
                vsel = selector + 3;
-               tps65910_reg_write_locked(pmic, TPS65911_VDDCTRL_OP, vsel);
+               tps65910_reg_write(pmic->mfd, TPS65911_VDDCTRL_OP, vsel);
        }
 
        return 0;
@@ -706,8 +629,8 @@ static int tps65910_set_voltage_sel(struct regulator_dev *dev,
        case TPS65910_REG_VAUX2:
        case TPS65910_REG_VAUX33:
        case TPS65910_REG_VMMC:
-               return tps65910_modify_bits(pmic, reg,
-                               (selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+               return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK,
+                                               selector << LDO_SEL_SHIFT);
        }
 
        return -EINVAL;
@@ -727,18 +650,18 @@ static int tps65911_set_voltage_sel(struct regulator_dev *dev,
        case TPS65911_REG_LDO1:
        case TPS65911_REG_LDO2:
        case TPS65911_REG_LDO4:
-               return tps65910_modify_bits(pmic, reg,
-                               (selector << LDO_SEL_SHIFT), LDO1_SEL_MASK);
+               return tps65910_reg_update_bits(pmic->mfd, reg, LDO1_SEL_MASK,
+                                               selector << LDO_SEL_SHIFT);
        case TPS65911_REG_LDO3:
        case TPS65911_REG_LDO5:
        case TPS65911_REG_LDO6:
        case TPS65911_REG_LDO7:
        case TPS65911_REG_LDO8:
-               return tps65910_modify_bits(pmic, reg,
-                               (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
+               return tps65910_reg_update_bits(pmic->mfd, reg, LDO3_SEL_MASK,
+                                               selector << LDO_SEL_SHIFT);
        case TPS65910_REG_VIO:
-               return tps65910_modify_bits(pmic, reg,
-                               (selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+               return tps65910_reg_update_bits(pmic->mfd, reg, LDO_SEL_MASK,
+                                               selector << LDO_SEL_SHIFT);
        }
 
        return -EINVAL;
@@ -768,23 +691,6 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
        return  volt * 100 * mult;
 }
 
-static int tps65910_list_voltage(struct regulator_dev *dev,
-                                       unsigned selector)
-{
-       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-       int id = rdev_get_id(dev), voltage;
-
-       if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
-               return -EINVAL;
-
-       if (selector >= pmic->info[id]->n_voltages)
-               return -EINVAL;
-       else
-               voltage = pmic->info[id]->voltage_table[selector] * 1000;
-
-       return voltage;
-}
-
 static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
@@ -816,7 +722,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
                step_mv = 100;
                break;
        case TPS65910_REG_VIO:
-               return pmic->info[id]->voltage_table[selector] * 1000;
+               return pmic->info[id]->voltage_table[selector];
        default:
                return -EINVAL;
        }
@@ -824,42 +730,16 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
        return (LDO_MIN_VOLT + selector * step_mv) * 1000;
 }
 
-static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev,
-               unsigned int old_selector, unsigned int new_selector)
-{
-       int id = rdev_get_id(dev);
-       int old_volt, new_volt;
-
-       old_volt = tps65910_list_voltage_dcdc(dev, old_selector);
-       if (old_volt < 0)
-               return old_volt;
-
-       new_volt = tps65910_list_voltage_dcdc(dev, new_selector);
-       if (new_volt < 0)
-               return new_volt;
-
-       /* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */
-       switch (id) {
-       case TPS65910_REG_VDD1:
-       case TPS65910_REG_VDD2:
-               return DIV_ROUND_UP(abs(old_volt - new_volt), 12500);
-       case TPS65911_REG_VDDCTRL:
-               return DIV_ROUND_UP(abs(old_volt - new_volt), 5000);
-       }
-       return -EINVAL;
-}
-
 /* Regulator ops (except VRTC) */
 static struct regulator_ops tps65910_ops_dcdc = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
-       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage_sel        = tps65910_get_voltage_dcdc_sel,
        .set_voltage_sel        = tps65910_set_voltage_dcdc_sel,
-       .set_voltage_time_sel   = tps65910_set_voltage_dcdc_time_sel,
+       .set_voltage_time_sel   = regulator_set_voltage_time_sel,
        .list_voltage           = tps65910_list_voltage_dcdc,
 };
 
@@ -867,30 +747,27 @@ static struct regulator_ops tps65910_ops_vdd3 = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
-       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage            = tps65910_get_voltage_vdd3,
-       .list_voltage           = tps65910_list_voltage,
+       .list_voltage           = regulator_list_voltage_table,
 };
 
 static struct regulator_ops tps65910_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
-       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage_sel        = tps65910_get_voltage_sel,
        .set_voltage_sel        = tps65910_set_voltage_sel,
-       .list_voltage           = tps65910_list_voltage,
+       .list_voltage           = regulator_list_voltage_table,
 };
 
 static struct regulator_ops tps65911_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
-       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage_sel        = tps65911_get_voltage_sel,
@@ -996,19 +873,27 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
                                (tps65910_chip_id(mfd) == TPS65911))) {
                int op_reg_add = pmic->get_ctrl_reg(id) + 1;
                int sr_reg_add = pmic->get_ctrl_reg(id) + 2;
-               int opvsel = tps65910_reg_read_locked(pmic, op_reg_add);
-               int srvsel = tps65910_reg_read_locked(pmic, sr_reg_add);
+               int opvsel, srvsel;
+
+               ret = tps65910_reg_read(pmic->mfd, op_reg_add, &opvsel);
+               if (ret < 0)
+                       return ret;
+               ret = tps65910_reg_read(pmic->mfd, sr_reg_add, &srvsel);
+               if (ret < 0)
+                       return ret;
+
                if (opvsel & VDD1_OP_CMD_MASK) {
                        u8 reg_val = srvsel & VDD1_OP_SEL_MASK;
-                       ret = tps65910_reg_write_locked(pmic, op_reg_add,
-                                                       reg_val);
+
+                       ret = tps65910_reg_write(pmic->mfd, op_reg_add,
+                                                reg_val);
                        if (ret < 0) {
                                dev_err(mfd->dev,
                                        "Error in configuring op register\n");
                                return ret;
                        }
                }
-               ret = tps65910_reg_write_locked(pmic, sr_reg_add, 0);
+               ret = tps65910_reg_write(pmic->mfd, sr_reg_add, 0);
                if (ret < 0) {
                        dev_err(mfd->dev, "Error in settting sr register\n");
                        return ret;
@@ -1126,6 +1011,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
                                "ti,regulator-ext-sleep-control", &prop);
                if (!ret)
                        pmic_plat_data->regulator_ext_sleep_control[idx] = prop;
+
        }
 
        return pmic_plat_data;
@@ -1136,7 +1022,7 @@ static inline struct tps65910_board *tps65910_parse_dt_reg_data(
                        struct of_regulator_match **tps65910_reg_matches)
 {
        *tps65910_reg_matches = NULL;
-       return 0;
+       return NULL;
 }
 #endif
 
@@ -1168,7 +1054,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       mutex_init(&pmic->mutex);
        pmic->mfd = tps65910;
        platform_set_drvdata(pdev, pmic);
 
@@ -1229,23 +1114,31 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
                pmic->info[i] = info;
 
                pmic->desc[i].name = info->name;
+               pmic->desc[i].supply_name = info->vin_name;
                pmic->desc[i].id = i;
                pmic->desc[i].n_voltages = info->n_voltages;
+               pmic->desc[i].enable_time = info->enable_time_us;
 
                if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
                        pmic->desc[i].ops = &tps65910_ops_dcdc;
                        pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE *
                                                        VDD1_2_NUM_VOLT_COARSE;
+                       pmic->desc[i].ramp_delay = 12500;
                } else if (i == TPS65910_REG_VDD3) {
-                       if (tps65910_chip_id(tps65910) == TPS65910)
+                       if (tps65910_chip_id(tps65910) == TPS65910) {
                                pmic->desc[i].ops = &tps65910_ops_vdd3;
-                       else
+                               pmic->desc[i].volt_table = info->voltage_table;
+                       } else {
                                pmic->desc[i].ops = &tps65910_ops_dcdc;
+                               pmic->desc[i].ramp_delay = 5000;
+                       }
                } else {
-                       if (tps65910_chip_id(tps65910) == TPS65910)
+                       if (tps65910_chip_id(tps65910) == TPS65910) {
                                pmic->desc[i].ops = &tps65910_ops;
-                       else
+                               pmic->desc[i].volt_table = info->voltage_table;
+                       } else {
                                pmic->desc[i].ops = &tps65911_ops;
+                       }
                }
 
                err = tps65910_set_ext_sleep_config(pmic, i,
index c7390711d9547e2762e818ae13cbdb8784fc29f4..242fe90dc56502ad5c5e1cc0ced284561b0e6df9 100644 (file)
@@ -43,9 +43,6 @@ struct twlreg_info {
        u8                      table_len;
        const u16               *table;
 
-       /* regulator specific turn-on delay */
-       u16                     delay;
-
        /* State REMAP default configuration */
        u8                      remap;
 
@@ -223,20 +220,6 @@ static int twl6030reg_enable(struct regulator_dev *rdev)
        return ret;
 }
 
-static int twl4030reg_enable_time(struct regulator_dev *rdev)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-
-       return info->delay;
-}
-
-static int twl6030reg_enable_time(struct regulator_dev *rdev)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-
-       return info->delay;
-}
-
 static int twl4030reg_disable(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
@@ -508,7 +491,6 @@ static struct regulator_ops twl4030ldo_ops = {
        .enable         = twl4030reg_enable,
        .disable        = twl4030reg_disable,
        .is_enabled     = twl4030reg_is_enabled,
-       .enable_time    = twl4030reg_enable_time,
 
        .set_mode       = twl4030reg_set_mode,
 
@@ -577,59 +559,53 @@ static struct regulator_ops twl6030coresmps_ops = {
        .get_voltage    = twl6030coresmps_get_voltage,
 };
 
-static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned sel)
 {
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
+       struct twlreg_info *info = rdev_get_drvdata(rdev);
 
-       return ((info->min_mV + (index * 100)) * 1000);
+       switch (sel) {
+       case 0:
+               return 0;
+       case 1 ... 24:
+               /* Linear mapping from 00000001 to 00011000:
+                * Absolute voltage value = 1.0 V + 0.1 V Ã— (sel â€“ 00000001)
+                */
+               return (info->min_mV + 100 * (sel - 1)) * 1000;
+       case 25 ... 30:
+               return -EINVAL;
+       case 31:
+               return 2750000;
+       default:
+               return -EINVAL;
+       }
 }
 
 static int
-twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
-                      unsigned *selector)
+twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int                     vsel;
-
-       if ((min_uV/1000 < info->min_mV) || (max_uV/1000 > info->max_mV))
-               return -EDOM;
-
-       /*
-        * Use the below formula to calculate vsel
-        * mV = 1000mv + 100mv * (vsel - 1)
-        */
-       vsel = (min_uV/1000 - 1000)/100 + 1;
-       *selector = vsel;
-       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel);
 
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE,
+                           selector);
 }
 
-static int twl6030ldo_get_voltage(struct regulator_dev *rdev)
+static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int             vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
-                                                               VREG_VOLTAGE);
-
-       if (vsel < 0)
-               return vsel;
+       int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE);
 
-       /*
-        * Use the below formula to calculate vsel
-        * mV = 1000mv + 100mv * (vsel - 1)
-        */
-       return (1000 + (100 * (vsel - 1))) * 1000;
+       return vsel;
 }
 
 static struct regulator_ops twl6030ldo_ops = {
        .list_voltage   = twl6030ldo_list_voltage,
 
-       .set_voltage    = twl6030ldo_set_voltage,
-       .get_voltage    = twl6030ldo_get_voltage,
+       .set_voltage_sel = twl6030ldo_set_voltage_sel,
+       .get_voltage_sel = twl6030ldo_get_voltage_sel,
 
        .enable         = twl6030reg_enable,
        .disable        = twl6030reg_disable,
        .is_enabled     = twl6030reg_is_enabled,
-       .enable_time    = twl6030reg_enable_time,
 
        .set_mode       = twl6030reg_set_mode,
 
@@ -663,7 +639,6 @@ static struct regulator_ops twl4030fixed_ops = {
        .enable         = twl4030reg_enable,
        .disable        = twl4030reg_disable,
        .is_enabled     = twl4030reg_is_enabled,
-       .enable_time    = twl4030reg_enable_time,
 
        .set_mode       = twl4030reg_set_mode,
 
@@ -678,7 +653,6 @@ static struct regulator_ops twl6030fixed_ops = {
        .enable         = twl6030reg_enable,
        .disable        = twl6030reg_disable,
        .is_enabled     = twl6030reg_is_enabled,
-       .enable_time    = twl6030reg_enable_time,
 
        .set_mode       = twl6030reg_set_mode,
 
@@ -689,7 +663,6 @@ static struct regulator_ops twl6030_fixed_resource = {
        .enable         = twl6030reg_enable,
        .disable        = twl6030reg_disable,
        .is_enabled     = twl6030reg_is_enabled,
-       .enable_time    = twl6030reg_enable_time,
        .get_status     = twl6030reg_get_status,
 };
 
@@ -886,7 +859,6 @@ static struct regulator_ops twlsmps_ops = {
        .enable                 = twl6030reg_enable,
        .disable                = twl6030reg_disable,
        .is_enabled             = twl6030reg_is_enabled,
-       .enable_time            = twl6030reg_enable_time,
 
        .set_mode               = twl6030reg_set_mode,
 
@@ -909,7 +881,6 @@ static struct twlreg_info TWL4030_INFO_##label = { \
        .id = num, \
        .table_len = ARRAY_SIZE(label##_VSEL_table), \
        .table = label##_VSEL_table, \
-       .delay = turnon_delay, \
        .remap = remap_conf, \
        .desc = { \
                .name = #label, \
@@ -918,6 +889,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \
                .ops = &twl4030ldo_ops, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
+               .enable_time = turnon_delay, \
                }, \
        }
 
@@ -925,7 +897,6 @@ static struct twlreg_info TWL4030_INFO_##label = { \
 static struct twlreg_info TWL4030_INFO_##label = { \
        .base = offset, \
        .id = num, \
-       .delay = turnon_delay, \
        .remap = remap_conf, \
        .desc = { \
                .name = #label, \
@@ -933,6 +904,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \
                .ops = &twl4030smps_ops, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
+               .enable_time = turnon_delay, \
                }, \
        }
 
@@ -955,7 +927,7 @@ static struct twlreg_info TWL6030_INFO_##label = { \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
-               .n_voltages = (max_mVolts - min_mVolts)/100 + 1, \
+               .n_voltages = 32, \
                .ops = &twl6030ldo_ops, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
@@ -970,7 +942,7 @@ static struct twlreg_info TWL6025_INFO_##label = { \
        .desc = { \
                .name = #label, \
                .id = TWL6025_REG_##label, \
-               .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \
+               .n_voltages = 32, \
                .ops = &twl6030ldo_ops, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
@@ -983,7 +955,6 @@ static struct twlreg_info TWLFIXED_INFO_##label = { \
        .base = offset, \
        .id = num, \
        .min_mV = mVolts, \
-       .delay = turnon_delay, \
        .remap = remap_conf, \
        .desc = { \
                .name = #label, \
@@ -992,19 +963,20 @@ static struct twlreg_info TWLFIXED_INFO_##label = { \
                .ops = &operations, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
+               .enable_time = turnon_delay, \
                }, \
        }
 
 #define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \
 static struct twlreg_info TWLRES_INFO_##label = { \
        .base = offset, \
-       .delay = turnon_delay, \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
                .ops = &twl6030_fixed_resource, \
                .type = REGULATOR_VOLTAGE, \
                .owner = THIS_MODULE, \
+               .enable_time = turnon_delay, \
                }, \
        }
 
@@ -1109,7 +1081,6 @@ static u8 twl_get_smps_mult(void)
 #define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label)
 #define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label)
 #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
-#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label)
 #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
 
 static const struct of_device_id twl_of_match[] __devinitconst = {
@@ -1157,7 +1128,6 @@ static const struct of_device_id twl_of_match[] __devinitconst = {
        TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB),
        TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8),
        TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1),
-       TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG),
        TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3),
        TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4),
        TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO),
index 099da11e989fde4e9ed793c3cdee9c6452c58a0f..7413885be01ba5907117c4c95d89df1a4129924b 100644 (file)
@@ -215,8 +215,8 @@ static int wm831x_buckv_list_voltage(struct regulator_dev *rdev,
        return -EINVAL;
 }
 
-static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
-                                          int min_uV, int max_uV)
+static int wm831x_buckv_map_voltage(struct regulator_dev *rdev,
+                                  int min_uV, int max_uV)
 {
        u16 vsel;
 
@@ -251,20 +251,14 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
        return 0;
 }
 
-static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV, unsigned *selector)
+static int wm831x_buckv_set_voltage_sel(struct regulator_dev *rdev,
+                                       unsigned vsel)
 {
        struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
        struct wm831x *wm831x = dcdc->wm831x;
        int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
        int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL;
-       int vsel, ret;
-
-       vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV);
-       if (vsel < 0)
-               return vsel;
-
-       *selector = vsel;
+       int ret;
 
        /* If this value is already set then do a GPIO update if we can */
        if (dcdc->dvs_gpio && dcdc->on_vsel == vsel)
@@ -315,7 +309,7 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev,
        u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
        int vsel;
 
-       vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV);
+       vsel = wm831x_buckv_map_voltage(rdev, uV, uV);
        if (vsel < 0)
                return vsel;
 
@@ -373,9 +367,10 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
 }
 
 static struct regulator_ops wm831x_buckv_ops = {
-       .set_voltage = wm831x_buckv_set_voltage,
+       .set_voltage_sel = wm831x_buckv_set_voltage_sel,
        .get_voltage_sel = wm831x_buckv_get_voltage_sel,
        .list_voltage = wm831x_buckv_list_voltage,
+       .map_voltage = wm831x_buckv_map_voltage,
        .set_suspend_voltage = wm831x_buckv_set_suspend_voltage,
        .set_current_limit = wm831x_buckv_set_current_limit,
        .get_current_limit = wm831x_buckv_get_current_limit,
@@ -599,60 +594,25 @@ static struct platform_driver wm831x_buckv_driver = {
  * BUCKP specifics
  */
 
-static int wm831x_buckp_list_voltage(struct regulator_dev *rdev,
-                                     unsigned selector)
-{
-       if (selector <= WM831X_BUCKP_MAX_SELECTOR)
-               return 850000 + (selector * 25000);
-       else
-               return -EINVAL;
-}
-
-static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg,
-                                       int min_uV, int max_uV, int *selector)
+static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
        struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
        struct wm831x *wm831x = dcdc->wm831x;
-       u16 vsel;
-
-       if (min_uV <= 34000000)
-               vsel = (min_uV - 850000) / 25000;
-       else
-               return -EINVAL;
-
-       if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV)
-               return -EINVAL;
-
-       *selector = vsel;
-
-       return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_buckp_set_voltage(struct regulator_dev *rdev,
-                                   int min_uV, int max_uV,
-                                   unsigned *selector)
-{
-       struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
-       u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG;
-
-       return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV,
-                                           selector);
-}
-
-static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev,
-                                           int uV)
-{
-       struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
        u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL;
-       unsigned selector;
+       int sel;
+
+       sel = regulator_map_voltage_linear(rdev, uV, uV);
+       if (sel < 0)
+               return sel;
 
-       return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector);
+       return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, sel);
 }
 
 static struct regulator_ops wm831x_buckp_ops = {
-       .set_voltage = wm831x_buckp_set_voltage,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .list_voltage = wm831x_buckp_list_voltage,
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
        .set_suspend_voltage = wm831x_buckp_set_suspend_voltage,
 
        .is_enabled = regulator_is_enabled_regmap,
@@ -715,6 +675,8 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
        dcdc->desc.vsel_mask = WM831X_DC3_ON_VSEL_MASK;
        dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
        dcdc->desc.enable_mask = 1 << id;
+       dcdc->desc.min_uV = 850000;
+       dcdc->desc.uV_step = 25000;
 
        config.dev = pdev->dev.parent;
        if (pdata)
index a9a28d8ac18591d4c7126364dbd40197024191f8..5cb70ca1e98d1f1843347fe14d7291d7a041eceb 100644 (file)
@@ -78,13 +78,10 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
        return -EINVAL;
 }
 
-static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
-                                        int min_uV, int max_uV,
-                                        unsigned *selector)
+static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev,
+                                    int min_uV, int max_uV)
 {
-       struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       struct wm831x *wm831x = ldo->wm831x;
-       int vsel, ret;
+       int volt, vsel;
 
        if (min_uV < 900000)
                vsel = 0;
@@ -94,36 +91,25 @@ static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg,
                vsel = ((min_uV - 1700000) / 100000)
                        + WM831X_GP_LDO_SELECTOR_LOW + 1;
 
-       ret = wm831x_gp_ldo_list_voltage(rdev, vsel);
-       if (ret < 0)
-               return ret;
-       if (ret < min_uV || ret > max_uV)
+       volt = wm831x_gp_ldo_list_voltage(rdev, vsel);
+       if (volt < min_uV || volt > max_uV)
                return -EINVAL;
 
-       *selector = vsel;
-
-       return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev,
-                                    int min_uV, int max_uV,
-                                    unsigned *selector)
-{
-       struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       int reg = ldo->base + WM831X_LDO_ON_CONTROL;
-
-       return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
-                                            selector);
+       return vsel;
 }
 
 static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
                                             int uV)
 {
        struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
-       unsigned int selector;
+       struct wm831x *wm831x = ldo->wm831x;
+       int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
 
-       return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+       sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV);
+       if (sel < 0)
+               return sel;
+
+       return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, sel);
 }
 
 static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
@@ -243,8 +229,9 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
 
 static struct regulator_ops wm831x_gp_ldo_ops = {
        .list_voltage = wm831x_gp_ldo_list_voltage,
+       .map_voltage = wm831x_gp_ldo_map_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage = wm831x_gp_ldo_set_voltage,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
        .get_mode = wm831x_gp_ldo_get_mode,
        .set_mode = wm831x_gp_ldo_set_mode,
@@ -384,13 +371,10 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
        return -EINVAL;
 }
 
-static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
-                                      int min_uV, int max_uV,
-                                      unsigned *selector)
+static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
+                                  int min_uV, int max_uV)
 {
-       struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       struct wm831x *wm831x = ldo->wm831x;
-       int vsel, ret;
+       int volt, vsel;
 
        if (min_uV < 1000000)
                vsel = 0;
@@ -400,35 +384,26 @@ static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg,
                vsel = ((min_uV - 1700000) / 100000)
                        + WM831X_ALDO_SELECTOR_LOW + 1;
 
-       ret = wm831x_aldo_list_voltage(rdev, vsel);
-       if (ret < 0)
-               return ret;
-       if (ret < min_uV || ret > max_uV)
+       volt = wm831x_aldo_list_voltage(rdev, vsel);
+       if (volt < min_uV || volt > max_uV)
                return -EINVAL;
 
-       *selector = vsel;
-
-       return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_aldo_set_voltage(struct regulator_dev *rdev,
-                                  int min_uV, int max_uV, unsigned *selector)
-{
-       struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       int reg = ldo->base + WM831X_LDO_ON_CONTROL;
+       return vsel;
 
-       return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV,
-                                          selector);
 }
 
 static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
                                             int uV)
 {
        struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
-       unsigned int selector;
+       struct wm831x *wm831x = ldo->wm831x;
+       int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
+
+       sel = wm831x_aldo_map_voltage(rdev, uV, uV);
+       if (sel < 0)
+               return sel;
 
-       return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+       return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel);
 }
 
 static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
@@ -506,8 +481,9 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
 
 static struct regulator_ops wm831x_aldo_ops = {
        .list_voltage = wm831x_aldo_list_voltage,
+       .map_voltage = wm831x_aldo_map_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage = wm831x_aldo_set_voltage,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
        .get_mode = wm831x_aldo_get_mode,
        .set_mode = wm831x_aldo_set_mode,
@@ -628,47 +604,18 @@ static struct platform_driver wm831x_aldo_driver = {
 
 #define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
 
-static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev,
-                                           int reg,
-                                           int min_uV, int max_uV,
-                                           unsigned *selector)
-{
-       struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       struct wm831x *wm831x = ldo->wm831x;
-       int vsel, ret;
-
-       vsel = (min_uV - 800000) / 50000;
-
-       ret = regulator_list_voltage_linear(rdev, vsel);
-       if (ret < 0)
-               return ret;
-       if (ret < min_uV || ret > max_uV)
-               return -EINVAL;
-
-       *selector = vsel;
-
-       return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel);
-}
-
-static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev,
-                                       int min_uV, int max_uV,
-                                       unsigned *selector)
-{
-       struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
-
-       return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV,
-                                               selector);
-}
-
 static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
                                             int uV)
 {
        struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
-       int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
-       unsigned selector;
+       struct wm831x *wm831x = ldo->wm831x;
+       int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
+
+       sel = regulator_map_voltage_linear(rdev, uV, uV);
+       if (sel < 0)
+               return sel;
 
-       return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector);
+       return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel);
 }
 
 static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
@@ -690,8 +637,9 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
 
 static struct regulator_ops wm831x_alive_ldo_ops = {
        .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
-       .set_voltage = wm831x_alive_ldo_set_voltage,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
        .get_status = wm831x_alive_ldo_get_status,
 
@@ -753,6 +701,7 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
        ldo->desc.enable_mask = 1 << id;
        ldo->desc.min_uV = 800000;
        ldo->desc.uV_step = 50000;
+       ldo->desc.enable_time = 1000;
 
        config.dev = pdev->dev.parent;
        if (pdata)
index 94e550dc70b64a6ef5042a68d2aa8dfef445bec2..7f0fa22ef2aab4e85e71693358737ee099b537e2 100644 (file)
@@ -108,33 +108,6 @@ static int get_isink_val(int min_uA, int max_uA, u16 *setting)
        return -EINVAL;
 }
 
-static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
-{
-       if (val < 16)
-               return (val * 50) + 900;
-       else
-               return ((val - 16) * 100) + 1800;
-
-}
-
-static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
-{
-       if (mV < 1800)
-               return (mV - 900) / 50;
-       else
-               return ((mV - 1800) / 100) + 16;
-}
-
-static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
-{
-       return (val * 25) + 850;
-}
-
-static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
-{
-       return (mV - 850) / 25;
-}
-
 static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
        int max_uA)
 {
@@ -359,104 +332,13 @@ int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
 }
 EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
 
-static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
-                                  int max_uV, unsigned *selector)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int volt_reg, dcdc = rdev_get_id(rdev), mV,
-               min_mV = min_uV / 1000, max_mV = max_uV / 1000;
-       u16 val;
-
-       if (min_mV < 850 || min_mV > 4025)
-               return -EINVAL;
-       if (max_mV < 850 || max_mV > 4025)
-               return -EINVAL;
-
-       /* step size is 25mV */
-       mV = (min_mV - 826) / 25;
-       if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
-               return -EINVAL;
-       BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
-
-       switch (dcdc) {
-       case WM8350_DCDC_1:
-               volt_reg = WM8350_DCDC1_CONTROL;
-               break;
-       case WM8350_DCDC_3:
-               volt_reg = WM8350_DCDC3_CONTROL;
-               break;
-       case WM8350_DCDC_4:
-               volt_reg = WM8350_DCDC4_CONTROL;
-               break;
-       case WM8350_DCDC_6:
-               volt_reg = WM8350_DCDC6_CONTROL;
-               break;
-       case WM8350_DCDC_2:
-       case WM8350_DCDC_5:
-       default:
-               return -EINVAL;
-       }
-
-       *selector = mV;
-
-       /* all DCDCs have same mV bits */
-       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
-       wm8350_reg_write(wm8350, volt_reg, val | mV);
-       return 0;
-}
-
-static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int volt_reg, dcdc = rdev_get_id(rdev);
-
-       switch (dcdc) {
-       case WM8350_DCDC_1:
-               volt_reg = WM8350_DCDC1_CONTROL;
-               break;
-       case WM8350_DCDC_3:
-               volt_reg = WM8350_DCDC3_CONTROL;
-               break;
-       case WM8350_DCDC_4:
-               volt_reg = WM8350_DCDC4_CONTROL;
-               break;
-       case WM8350_DCDC_6:
-               volt_reg = WM8350_DCDC6_CONTROL;
-               break;
-       case WM8350_DCDC_2:
-       case WM8350_DCDC_5:
-       default:
-               return -EINVAL;
-       }
-
-       /* all DCDCs have same mV bits */
-       return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
-}
-
-static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
-                                   unsigned selector)
-{
-       if (selector > WM8350_DCDC_MAX_VSEL)
-               return -EINVAL;
-       return wm8350_dcdc_val_to_mvolts(selector) * 1000;
-}
-
 static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
        struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+       int sel, volt_reg, dcdc = rdev_get_id(rdev);
        u16 val;
 
-       dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
-
-       if (mV && (mV < 850 || mV > 4025)) {
-               dev_err(wm8350->dev,
-                       "DCDC%d suspend voltage %d mV out of range\n",
-                       dcdc, mV);
-               return -EINVAL;
-       }
-       if (mV == 0)
-               mV = 850;
+       dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, uV / 1000);
 
        switch (dcdc) {
        case WM8350_DCDC_1:
@@ -477,10 +359,13 @@ static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
                return -EINVAL;
        }
 
+       sel = regulator_map_voltage_linear(rdev, uV, uV);
+       if (sel < 0)
+               return -EINVAL;
+
        /* all DCDCs have same mV bits */
        val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
-       wm8350_reg_write(wm8350, volt_reg,
-                        val | wm8350_dcdc_mvolts_to_val(mV));
+       wm8350_reg_write(wm8350, volt_reg, val | sel);
        return 0;
 }
 
@@ -657,19 +542,49 @@ static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
        return 0;
 }
 
+static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
+                                   unsigned selector)
+{
+       if (selector > WM8350_LDO1_VSEL_MASK)
+               return -EINVAL;
+
+       if (selector < 16)
+               return (selector * 50000) + 900000;
+       else
+               return ((selector - 16) * 100000) + 1800000;
+}
+
+static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV,
+                                 int max_uV)
+{
+       int volt, sel;
+       int min_mV = min_uV / 1000;
+       int max_mV = max_uV / 1000;
+
+       if (min_mV < 900 || min_mV > 3300)
+               return -EINVAL;
+       if (max_mV < 900 || max_mV > 3300)
+               return -EINVAL;
+
+       if (min_mV < 1800) /* step size is 50mV < 1800mV */
+               sel = DIV_ROUND_UP(min_uV - 900, 50);
+       else /* step size is 100mV > 1800mV */
+               sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16;
+
+       volt = wm8350_ldo_list_voltage(rdev, sel);
+       if (volt < min_uV || volt > max_uV)
+               return -EINVAL;
+
+       return sel;
+}
+
 static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
        struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+       int sel, volt_reg, ldo = rdev_get_id(rdev);
        u16 val;
 
-       dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
-
-       if (mV < 900 || mV > 3300) {
-               dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
-                       ldo, mV);
-               return -EINVAL;
-       }
+       dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, uV / 1000);
 
        switch (ldo) {
        case WM8350_LDO_1:
@@ -688,10 +603,13 @@ static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
                return -EINVAL;
        }
 
+       sel = wm8350_ldo_map_voltage(rdev, uV, uV);
+       if (sel < 0)
+               return -EINVAL;
+
        /* all LDOs have same mV bits */
        val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
-       wm8350_reg_write(wm8350, volt_reg,
-                        val | wm8350_ldo_mvolts_to_val(mV));
+       wm8350_reg_write(wm8350, volt_reg, val | sel);
        return 0;
 }
 
@@ -753,92 +671,6 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
        return 0;
 }
 
-static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
-                                 int max_uV, unsigned *selector)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
-               max_mV = max_uV / 1000;
-       u16 val;
-
-       if (min_mV < 900 || min_mV > 3300)
-               return -EINVAL;
-       if (max_mV < 900 || max_mV > 3300)
-               return -EINVAL;
-
-       if (min_mV < 1800) {
-               /* step size is 50mV < 1800mV */
-               mV = (min_mV - 851) / 50;
-               if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
-                       return -EINVAL;
-               BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
-       } else {
-               /* step size is 100mV > 1800mV */
-               mV = ((min_mV - 1701) / 100) + 16;
-               if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
-                       return -EINVAL;
-               BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
-       }
-
-       switch (ldo) {
-       case WM8350_LDO_1:
-               volt_reg = WM8350_LDO1_CONTROL;
-               break;
-       case WM8350_LDO_2:
-               volt_reg = WM8350_LDO2_CONTROL;
-               break;
-       case WM8350_LDO_3:
-               volt_reg = WM8350_LDO3_CONTROL;
-               break;
-       case WM8350_LDO_4:
-               volt_reg = WM8350_LDO4_CONTROL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       *selector = mV;
-
-       /* all LDOs have same mV bits */
-       val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
-       wm8350_reg_write(wm8350, volt_reg, val | mV);
-       return 0;
-}
-
-static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int volt_reg, ldo = rdev_get_id(rdev);
-
-       switch (ldo) {
-       case WM8350_LDO_1:
-               volt_reg = WM8350_LDO1_CONTROL;
-               break;
-       case WM8350_LDO_2:
-               volt_reg = WM8350_LDO2_CONTROL;
-               break;
-       case WM8350_LDO_3:
-               volt_reg = WM8350_LDO3_CONTROL;
-               break;
-       case WM8350_LDO_4:
-               volt_reg = WM8350_LDO4_CONTROL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* all LDOs have same mV bits */
-       return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
-}
-
-static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
-                                   unsigned selector)
-{
-       if (selector > WM8350_LDO1_VSEL_MASK)
-               return -EINVAL;
-       return wm8350_ldo_val_to_mvolts(selector) * 1000;
-}
-
 int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
                         u16 stop, u16 fault)
 {
@@ -959,63 +791,6 @@ int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
 }
 EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
 
-static int wm8350_dcdc_enable(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int dcdc = rdev_get_id(rdev);
-       u16 shift;
-
-       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
-               return -EINVAL;
-
-       shift = dcdc - WM8350_DCDC_1;
-       wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-       return 0;
-}
-
-static int wm8350_dcdc_disable(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int dcdc = rdev_get_id(rdev);
-       u16 shift;
-
-       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
-               return -EINVAL;
-
-       shift = dcdc - WM8350_DCDC_1;
-       wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-
-       return 0;
-}
-
-static int wm8350_ldo_enable(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int ldo = rdev_get_id(rdev);
-       u16 shift;
-
-       if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
-               return -EINVAL;
-
-       shift = (ldo - WM8350_LDO_1) + 8;
-       wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-       return 0;
-}
-
-static int wm8350_ldo_disable(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int ldo = rdev_get_id(rdev);
-       u16 shift;
-
-       if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
-               return -EINVAL;
-
-       shift = (ldo - WM8350_LDO_1) + 8;
-       wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
-       return 0;
-}
-
 static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
 {
        int reg = 0, ret;
@@ -1197,42 +972,17 @@ static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
        return mode;
 }
 
-static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int dcdc = rdev_get_id(rdev), shift;
-
-       if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
-               return -EINVAL;
-
-       shift = dcdc - WM8350_DCDC_1;
-       return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
-           & (1 << shift);
-}
-
-static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
-{
-       struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
-       int ldo = rdev_get_id(rdev), shift;
-
-       if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
-               return -EINVAL;
-
-       shift = (ldo - WM8350_LDO_1) + 8;
-       return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
-           & (1 << shift);
-}
-
 static struct regulator_ops wm8350_dcdc_ops = {
-       .set_voltage = wm8350_dcdc_set_voltage,
-       .get_voltage_sel = wm8350_dcdc_get_voltage_sel,
-       .list_voltage = wm8350_dcdc_list_voltage,
-       .enable = wm8350_dcdc_enable,
-       .disable = wm8350_dcdc_disable,
+       .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,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
        .get_mode = wm8350_dcdc_get_mode,
        .set_mode = wm8350_dcdc_set_mode,
        .get_optimum_mode = wm8350_dcdc_get_optimum_mode,
-       .is_enabled = wm8350_dcdc_is_enabled,
        .set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
        .set_suspend_enable = wm8350_dcdc_set_suspend_enable,
        .set_suspend_disable = wm8350_dcdc_set_suspend_disable,
@@ -1240,20 +990,21 @@ static struct regulator_ops wm8350_dcdc_ops = {
 };
 
 static struct regulator_ops wm8350_dcdc2_5_ops = {
-       .enable = wm8350_dcdc_enable,
-       .disable = wm8350_dcdc_disable,
-       .is_enabled = wm8350_dcdc_is_enabled,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
        .set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
        .set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
 };
 
 static struct regulator_ops wm8350_ldo_ops = {
-       .set_voltage = wm8350_ldo_set_voltage,
-       .get_voltage_sel = wm8350_ldo_get_voltage_sel,
+       .map_voltage = wm8350_ldo_map_voltage,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .list_voltage = wm8350_ldo_list_voltage,
-       .enable = wm8350_ldo_enable,
-       .disable = wm8350_ldo_disable,
-       .is_enabled = wm8350_ldo_is_enabled,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
        .get_mode = wm8350_ldo_get_mode,
        .set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
        .set_suspend_enable = wm8350_ldo_set_suspend_enable,
@@ -1277,6 +1028,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_DC1,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+               .min_uV = 850000,
+               .uV_step = 25000,
+               .vsel_reg = WM8350_DCDC1_CONTROL,
+               .vsel_mask = WM8350_DC1_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_DC1_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1285,6 +1042,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_dcdc2_5_ops,
                .irq = WM8350_IRQ_UV_DC2,
                .type = REGULATOR_VOLTAGE,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_DC2_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1294,6 +1053,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_DC3,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+               .min_uV = 850000,
+               .uV_step = 25000,
+               .vsel_reg = WM8350_DCDC3_CONTROL,
+               .vsel_mask = WM8350_DC3_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_DC3_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1303,6 +1068,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_DC4,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+               .min_uV = 850000,
+               .uV_step = 25000,
+               .vsel_reg = WM8350_DCDC4_CONTROL,
+               .vsel_mask = WM8350_DC4_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_DC4_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1311,6 +1082,8 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .ops = &wm8350_dcdc2_5_ops,
                .irq = WM8350_IRQ_UV_DC5,
                .type = REGULATOR_VOLTAGE,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_DC5_ENA,
                .owner = THIS_MODULE,
         },
        {
@@ -1320,6 +1093,12 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_DC6,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_DCDC_MAX_VSEL + 1,
+               .min_uV = 850000,
+               .uV_step = 25000,
+               .vsel_reg = WM8350_DCDC6_CONTROL,
+               .vsel_mask = WM8350_DC6_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_DC6_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1329,6 +1108,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO1,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO1_VSEL_MASK + 1,
+               .vsel_reg = WM8350_LDO1_CONTROL,
+               .vsel_mask = WM8350_LDO1_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_LDO1_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1338,6 +1121,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO2,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO2_VSEL_MASK + 1,
+               .vsel_reg = WM8350_LDO2_CONTROL,
+               .vsel_mask = WM8350_LDO2_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_LDO2_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1347,6 +1134,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO3,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO3_VSEL_MASK + 1,
+               .vsel_reg = WM8350_LDO3_CONTROL,
+               .vsel_mask = WM8350_LDO3_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_LDO3_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1356,6 +1147,10 @@ static const struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
                .irq = WM8350_IRQ_UV_LDO4,
                .type = REGULATOR_VOLTAGE,
                .n_voltages = WM8350_LDO4_VSEL_MASK + 1,
+               .vsel_reg = WM8350_LDO4_CONTROL,
+               .vsel_mask = WM8350_LDO4_VSEL_MASK,
+               .enable_reg = WM8350_DCDC_LDO_REQUESTED,
+               .enable_mask = WM8350_LDO4_ENA,
                .owner = THIS_MODULE,
        },
        {
@@ -1429,6 +1224,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
        config.dev = &pdev->dev;
        config.init_data = pdev->dev.platform_data;
        config.driver_data = dev_get_drvdata(&pdev->dev);
+       config.regmap = wm8350->regmap;
 
        /* register regulator */
        rdev = regulator_register(&wm8350_reg[pdev->id], &config);
index 69a2b7ce5e4a09a3dae1e606aaf3786011dd02b2..9035dd0536118df253769b6e7e5847621ebd9a5e 100644 (file)
@@ -28,34 +28,26 @@ static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
        if (selector < 15)
                return 900000 + (selector * 50000);
        else
-               return 1600000 + ((selector - 14) * 100000);
+               return 1700000 + ((selector - 15) * 100000);
 }
 
 static int wm8400_ldo_map_voltage(struct regulator_dev *dev,
                                  int min_uV, int max_uV)
 {
        u16 val;
+       int volt;
 
        if (min_uV < 900000 || min_uV > 3300000)
                return -EINVAL;
 
-       if (min_uV < 1700000) {
-               /* Steps of 50mV from 900mV;  */
+       if (min_uV < 1700000) /* Steps of 50mV from 900mV;  */
                val = DIV_ROUND_UP(min_uV - 900000, 50000);
+       else /* Steps of 100mV from 1700mV */
+               val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15;
 
-               if ((val * 50000) + 900000 > max_uV)
-                       return -EINVAL;
-               BUG_ON((val * 50000) + 900000 < min_uV);
-       } else {
-               /* Steps of 100mV from 1700mV */
-               val = DIV_ROUND_UP(min_uV - 1700000, 100000);
-
-               if ((val * 100000) + 1700000 > max_uV)
-                       return -EINVAL;
-               BUG_ON((val * 100000) + 1700000 < min_uV);
-
-               val += 0xf;
-       }
+       volt = wm8400_ldo_list_voltage(dev, val);
+       if (volt < min_uV || volt > max_uV)
+               return -EINVAL;
 
        return val;
 }
@@ -152,6 +144,7 @@ static struct regulator_ops wm8400_dcdc_ops = {
        .enable = regulator_enable_regmap,
        .disable = regulator_disable_regmap,
        .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
        .get_mode = wm8400_dcdc_get_mode,
index 9a994316e63c60b748d0afea65ffc123e81fcf09..86bb48db149ed3d2bb1285f9dd4a24fb28a531f2 100644 (file)
@@ -26,8 +26,6 @@
 #include <linux/mfd/wm8994/pdata.h>
 
 struct wm8994_ldo {
-       int enable;
-       bool is_enabled;
        struct regulator_dev *regulator;
        struct wm8994 *wm8994;
 };
@@ -35,64 +33,9 @@ struct wm8994_ldo {
 #define WM8994_LDO1_MAX_SELECTOR 0x7
 #define WM8994_LDO2_MAX_SELECTOR 0x3
 
-static int wm8994_ldo_enable(struct regulator_dev *rdev)
-{
-       struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
-       /* If we have no soft control assume that the LDO is always enabled. */
-       if (!ldo->enable)
-               return 0;
-
-       gpio_set_value_cansleep(ldo->enable, 1);
-       ldo->is_enabled = true;
-
-       return 0;
-}
-
-static int wm8994_ldo_disable(struct regulator_dev *rdev)
-{
-       struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
-       /* If we have no soft control assume that the LDO is always enabled. */
-       if (!ldo->enable)
-               return -EINVAL;
-
-       gpio_set_value_cansleep(ldo->enable, 0);
-       ldo->is_enabled = false;
-
-       return 0;
-}
-
-static int wm8994_ldo_is_enabled(struct regulator_dev *rdev)
-{
-       struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
-       return ldo->is_enabled;
-}
-
-static int wm8994_ldo_enable_time(struct regulator_dev *rdev)
-{
-       /* 3ms is fairly conservative but this shouldn't be too performance
-        * critical; can be tweaked per-system if required. */
-       return 3000;
-}
-
-static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
-                                   unsigned int selector)
-{
-       if (selector > WM8994_LDO1_MAX_SELECTOR)
-               return -EINVAL;
-
-       return (selector * 100000) + 2400000;
-}
-
 static struct regulator_ops wm8994_ldo1_ops = {
-       .enable = wm8994_ldo_enable,
-       .disable = wm8994_ldo_disable,
-       .is_enabled = wm8994_ldo_is_enabled,
-       .enable_time = wm8994_ldo_enable_time,
-
-       .list_voltage = wm8994_ldo1_list_voltage,
+       .list_voltage = regulator_list_voltage_linear,
+       .map_voltage = regulator_map_voltage_linear,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
 };
@@ -124,11 +67,6 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
 }
 
 static struct regulator_ops wm8994_ldo2_ops = {
-       .enable = wm8994_ldo_enable,
-       .disable = wm8994_ldo_disable,
-       .is_enabled = wm8994_ldo_is_enabled,
-       .enable_time = wm8994_ldo_enable_time,
-
        .list_voltage = wm8994_ldo2_list_voltage,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -143,6 +81,9 @@ static const struct regulator_desc wm8994_ldo_desc[] = {
                .vsel_reg = WM8994_LDO_1,
                .vsel_mask = WM8994_LDO1_VSEL_MASK,
                .ops = &wm8994_ldo1_ops,
+               .min_uV = 2400000,
+               .uV_step = 100000,
+               .enable_time = 3000,
                .owner = THIS_MODULE,
        },
        {
@@ -153,6 +94,7 @@ static const struct regulator_desc wm8994_ldo_desc[] = {
                .vsel_reg = WM8994_LDO_2,
                .vsel_mask = WM8994_LDO2_VSEL_MASK,
                .ops = &wm8994_ldo2_ops,
+               .enable_time = 3000,
                .owner = THIS_MODULE,
        },
 };
@@ -176,39 +118,26 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
 
        ldo->wm8994 = wm8994;
 
-       if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
-               ldo->enable = pdata->ldo[id].enable;
-
-               ret = gpio_request_one(ldo->enable, 0, "WM8994 LDO enable");
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n",
-                               ret);
-                       goto err;
-               }
-       } else
-               ldo->is_enabled = true;
-
        config.dev = wm8994->dev;
        config.driver_data = ldo;
        config.regmap = wm8994->regmap;
-       if (pdata)
+       if (pdata) {
                config.init_data = pdata->ldo[id].init_data;
+               config.ena_gpio = pdata->ldo[id].enable;
+       }
 
        ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config);
        if (IS_ERR(ldo->regulator)) {
                ret = PTR_ERR(ldo->regulator);
                dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
                        id + 1, ret);
-               goto err_gpio;
+               goto err;
        }
 
        platform_set_drvdata(pdev, ldo);
 
        return 0;
 
-err_gpio:
-       if (gpio_is_valid(ldo->enable))
-               gpio_free(ldo->enable);
 err:
        return ret;
 }
@@ -220,8 +149,6 @@ static __devexit int wm8994_ldo_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        regulator_unregister(ldo->regulator);
-       if (gpio_is_valid(ldo->enable))
-               gpio_free(ldo->enable);
 
        return 0;
 }
index 24d880e78ec6704e8b84e6d0f6547602f1f639bb..f8d818abf98caf4dc8275a65e18695c41c639537 100644 (file)
@@ -4,9 +4,11 @@ menu "Remoteproc drivers (EXPERIMENTAL)"
 config REMOTEPROC
        tristate
        depends on EXPERIMENTAL
+       select FW_CONFIG
 
 config OMAP_REMOTEPROC
        tristate "OMAP remoteproc support"
+       depends on EXPERIMENTAL
        depends on ARCH_OMAP4
        depends on OMAP_IOMMU
        select REMOTEPROC
index 75506ec2840e2ec4d1e331f209377d874f604386..f56c8ba3a861cda16870e7456391fe564ec741c6 100644 (file)
@@ -188,6 +188,26 @@ static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
                                        rpdev->id.name);
 }
 
+/**
+ * __ept_release() - deallocate an rpmsg endpoint
+ * @kref: the ept's reference count
+ *
+ * This function deallocates an ept, and is invoked when its @kref refcount
+ * drops to zero.
+ *
+ * Never invoke this function directly!
+ */
+static void __ept_release(struct kref *kref)
+{
+       struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint,
+                                                 refcount);
+       /*
+        * At this point no one holds a reference to ept anymore,
+        * so we can directly free it
+        */
+       kfree(ept);
+}
+
 /* for more info, see below documentation of rpmsg_create_ept() */
 static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
                struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb,
@@ -206,6 +226,9 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
                return NULL;
        }
 
+       kref_init(&ept->refcount);
+       mutex_init(&ept->cb_lock);
+
        ept->rpdev = rpdev;
        ept->cb = cb;
        ept->priv = priv;
@@ -238,7 +261,7 @@ rem_idr:
        idr_remove(&vrp->endpoints, request);
 free_ept:
        mutex_unlock(&vrp->endpoints_lock);
-       kfree(ept);
+       kref_put(&ept->refcount, __ept_release);
        return NULL;
 }
 
@@ -302,11 +325,17 @@ EXPORT_SYMBOL(rpmsg_create_ept);
 static void
 __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
 {
+       /* make sure new inbound messages can't find this ept anymore */
        mutex_lock(&vrp->endpoints_lock);
        idr_remove(&vrp->endpoints, ept->addr);
        mutex_unlock(&vrp->endpoints_lock);
 
-       kfree(ept);
+       /* make sure in-flight inbound messages won't invoke cb anymore */
+       mutex_lock(&ept->cb_lock);
+       ept->cb = NULL;
+       mutex_unlock(&ept->cb_lock);
+
+       kref_put(&ept->refcount, __ept_release);
 }
 
 /**
@@ -790,12 +819,28 @@ static void rpmsg_recv_done(struct virtqueue *rvq)
 
        /* use the dst addr to fetch the callback of the appropriate user */
        mutex_lock(&vrp->endpoints_lock);
+
        ept = idr_find(&vrp->endpoints, msg->dst);
+
+       /* let's make sure no one deallocates ept while we use it */
+       if (ept)
+               kref_get(&ept->refcount);
+
        mutex_unlock(&vrp->endpoints_lock);
 
-       if (ept && ept->cb)
-               ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src);
-       else
+       if (ept) {
+               /* make sure ept->cb doesn't go away while we use it */
+               mutex_lock(&ept->cb_lock);
+
+               if (ept->cb)
+                       ept->cb(ept->rpdev, msg->data, msg->len, ept->priv,
+                               msg->src);
+
+               mutex_unlock(&ept->cb_lock);
+
+               /* farewell, ept, we don't need you anymore */
+               kref_put(&ept->refcount, __ept_release);
+       } else
                dev_warn(dev, "msg received with no recepient\n");
 
        /* publish the real size of the buffer */
@@ -1040,7 +1085,7 @@ static int __init rpmsg_init(void)
 
        return ret;
 }
-module_init(rpmsg_init);
+subsys_initcall(rpmsg_init);
 
 static void __exit rpmsg_fini(void)
 {
index 4bcf9ca2818ae740eadd016df48cc0461da23f6e..370889d0489bf9e4f196abcbbcd6f11b25e6f5a8 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 
 #define AB8500_RTC_SOFF_STAT_REG       0x00
 #define AB8500_RTC_CC_CONF_REG         0x01
@@ -422,7 +423,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
        }
 
        err = request_threaded_irq(irq, NULL, rtc_alarm_handler,
-               IRQF_NO_SUSPEND, "ab8500-rtc", rtc);
+               IRQF_NO_SUSPEND | IRQF_ONESHOT, "ab8500-rtc", rtc);
        if (err < 0) {
                rtc_device_unregister(rtc);
                return err;
@@ -430,7 +431,6 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, rtc);
 
-
        err = ab8500_sysfs_rtc_register(&pdev->dev);
        if (err) {
                dev_err(&pdev->dev, "sysfs RTC failed to register\n");
@@ -454,10 +454,16 @@ static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id ab8500_rtc_match[] = {
+       { .compatible = "stericsson,ab8500-rtc", },
+       {}
+};
+
 static struct platform_driver ab8500_rtc_driver = {
        .driver = {
                .name = "ab8500-rtc",
                .owner = THIS_MODULE,
+               .of_match_table = ab8500_rtc_match,
        },
        .probe  = ab8500_rtc_probe,
        .remove = __devexit_p(ab8500_rtc_remove),
index dc474bc6522de1d44295f67ad3ddb1f7bc33a771..fca9790c7de75550d6e9700be52ee0d019762531 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioctl.h>
 #include <linux/completion.h>
+#include <linux/io.h>
 
 #include <asm/uaccess.h>
 
index 4267789ca9959413e90df5ea053154e07481d3ce..132333d754085d6b06a9c096444a95b708e45893 100644 (file)
@@ -568,6 +568,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
                hpet_mask_rtc_irq_bit(RTC_AIE);
 
                CMOS_READ(RTC_INTR_FLAGS);
+               pm_wakeup_event(cmos_rtc.dev, 0);
        }
        spin_unlock(&rtc_lock);
 
index 5e1d64ee52289b9e7a47990f8c7de0b41c7fccaf..e3e50d69baf85e75966bdea6d7f7b95ae6d65af0 100644 (file)
@@ -202,10 +202,11 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
        struct platform_device *pdev = dev_id;
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
        void __iomem *ioaddr = pdata->ioaddr;
+       unsigned long flags;
        u32 status;
        u32 events = 0;
 
-       spin_lock_irq(&pdata->rtc->irq_lock);
+       spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
        status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR);
        /* clear interrupt sources */
        writew(status, ioaddr + RTC_RTCISR);
@@ -224,7 +225,7 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
                events |= (RTC_PF | RTC_IRQF);
 
        rtc_update_irq(pdata->rtc, 1, events);
-       spin_unlock_irq(&pdata->rtc->irq_lock);
+       spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
 
        return IRQ_HANDLED;
 }
index 1f76320e545b1cf15d563cc8996b8eed7122f14a..e2785479113ca06648949d6c6a78adee92c78367 100644 (file)
@@ -458,12 +458,12 @@ static int __devexit spear_rtc_remove(struct platform_device *pdev)
        clk_disable(config->clk);
        clk_put(config->clk);
        iounmap(config->ioaddr);
-       kfree(config);
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res)
                release_mem_region(res->start, resource_size(res));
        platform_set_drvdata(pdev, NULL);
        rtc_device_unregister(config->rtc);
+       kfree(config);
 
        return 0;
 }
index 10287865e33012a154100b6b674f541273d132d3..739ef55694f4d30c6d7370ae66c5ad42e996430f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/interrupt.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
+#include <linux/of_device.h>
 
 #include <mach/common.h>
 
@@ -265,6 +266,12 @@ static int stmp3xxx_rtc_resume(struct platform_device *dev)
 #define stmp3xxx_rtc_resume    NULL
 #endif
 
+static const struct of_device_id rtc_dt_ids[] = {
+       { .compatible = "fsl,stmp3xxx-rtc", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rtc_dt_ids);
+
 static struct platform_driver stmp3xxx_rtcdrv = {
        .probe          = stmp3xxx_rtc_probe,
        .remove         = stmp3xxx_rtc_remove,
@@ -273,6 +280,7 @@ static struct platform_driver stmp3xxx_rtcdrv = {
        .driver         = {
                .name   = "stmp3xxx-rtc",
                .owner  = THIS_MODULE,
+               .of_match_table = rtc_dt_ids,
        },
 };
 
index 258abeabf6246a1ed7e4db116713bb3128009fa0..c5d06fe83bba6274f2e6b944a43489395e04e01c 100644 (file)
@@ -510,7 +510,7 @@ static int __devinit twl_rtc_probe(struct platform_device *pdev)
        }
 
        ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
-                                  IRQF_TRIGGER_RISING,
+                                  IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                                   dev_name(&rtc->dev), rtc);
        if (ret < 0) {
                dev_err(&pdev->dev, "IRQ is not free.\n");
index 532d212b6b2c7b633a9b4338da14c78439a1d3db..393e7ce8e95a15ef5907c820dcb2ff9bd3542ac8 100644 (file)
@@ -201,7 +201,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
 
                if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
                        resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
-                       memcpy(&resp->ending_fis[0], r+16, 24);
+                       memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE);
                        ts->buf_valid_size = sizeof(*resp);
                }
        }
index 0c53c28dc3d379a5a09960e2e9ab8fae53cb8526..7e77cf62029190562d718fe7c365cb087c3e573e 100644 (file)
@@ -350,6 +350,7 @@ struct bnx2i_hba {
        struct pci_dev *pcidev;
        struct net_device *netdev;
        void __iomem *regview;
+       resource_size_t reg_base;
 
        u32 age;
        unsigned long cnic_dev_type;
index ece47e502282d389b91e5d170ca023688a22deb6..86a12b48e477e804e12765e7d535d7e70f44405e 100644 (file)
@@ -2724,7 +2724,6 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
                goto arm_cq;
        }
 
-       reg_base = ep->hba->netdev->base_addr;
        if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) &&
            (ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) {
                config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2);
@@ -2740,7 +2739,7 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
                /* 5709 device in normal node and 5706/5708 devices */
                reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
 
-       ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off,
+       ep->qp.ctx_base = ioremap_nocache(ep->hba->reg_base + reg_off,
                                          MB_KERNEL_CTX_SIZE);
        if (!ep->qp.ctx_base)
                return -ENOMEM;
index f8d516b531617426cc05d626188075facf4e5a6a..621538b8b5445fd3e3e2685213ae7118f7229fd0 100644 (file)
@@ -811,13 +811,13 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
        bnx2i_identify_device(hba);
        bnx2i_setup_host_queue_size(hba, shost);
 
+       hba->reg_base = pci_resource_start(hba->pcidev, 0);
        if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) {
-               hba->regview = ioremap_nocache(hba->netdev->base_addr,
-                                              BNX2_MQ_CONFIG2);
+               hba->regview = pci_iomap(hba->pcidev, 0, BNX2_MQ_CONFIG2);
                if (!hba->regview)
                        goto ioreg_map_err;
        } else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) {
-               hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096);
+               hba->regview = pci_iomap(hba->pcidev, 0, 4096);
                if (!hba->regview)
                        goto ioreg_map_err;
        }
@@ -884,7 +884,7 @@ cid_que_err:
        bnx2i_free_mp_bdt(hba);
 mp_bdt_mem_err:
        if (hba->regview) {
-               iounmap(hba->regview);
+               pci_iounmap(hba->pcidev, hba->regview);
                hba->regview = NULL;
        }
 ioreg_map_err:
@@ -910,7 +910,7 @@ void bnx2i_free_hba(struct bnx2i_hba *hba)
        pci_dev_put(hba->pcidev);
 
        if (hba->regview) {
-               iounmap(hba->regview);
+               pci_iounmap(hba->pcidev, hba->regview);
                hba->regview = NULL;
        }
        bnx2i_free_mp_bdt(hba);
index 441d88ad99a7bb3abadb8b1e9af25281ced8334b..d109cc3a17b64126ee9ff38a5da320a070ffc2c5 100644 (file)
@@ -139,12 +139,12 @@ static void sas_ata_task_done(struct sas_task *task)
        if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
            ((stat->stat == SAM_STAT_CHECK_CONDITION &&
              dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
-               ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
+               memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE);
 
                if (!link->sactive) {
-                       qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+                       qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
                } else {
-                       link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+                       link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]);
                        if (unlikely(link->eh_info.err_mask))
                                qc->flags |= ATA_QCFLAG_FAILED;
                }
@@ -161,8 +161,8 @@ static void sas_ata_task_done(struct sas_task *task)
                                qc->flags |= ATA_QCFLAG_FAILED;
                        }
 
-                       dev->sata_dev.tf.feature = 0x04; /* status err */
-                       dev->sata_dev.tf.command = ATA_ERR;
+                       dev->sata_dev.fis[3] = 0x04; /* status err */
+                       dev->sata_dev.fis[2] = ATA_ERR;
                }
        }
 
@@ -269,7 +269,7 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
 {
        struct domain_device *dev = qc->ap->private_data;
 
-       memcpy(&qc->result_tf, &dev->sata_dev.tf, sizeof(qc->result_tf));
+       ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf);
        return true;
 }
 
index 6986552b47e6f6af591681fa4f14dbe3c0b11a6f..5b30132960c7901e514948c092ab105f43b483a0 100644 (file)
@@ -2643,19 +2643,9 @@ static void qlt_do_work(struct work_struct *work)
        spin_lock_irqsave(&ha->hardware_lock, flags);
        sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha,
            atio->u.isp24.fcp_hdr.s_id);
-       if (sess) {
-               if (unlikely(sess->tearing_down)) {
-                       sess = NULL;
-                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
-                       goto out_term;
-               } else {
-                       /*
-                        * Do the extra kref_get() before dropping
-                        * qla_hw_data->hardware_lock.
-                        */
-                       kref_get(&sess->se_sess->sess_kref);
-               }
-       }
+       /* Do kref_get() before dropping qla_hw_data->hardware_lock. */
+       if (sess)
+               kref_get(&sess->se_sess->sess_kref);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        if (unlikely(!sess)) {
@@ -3960,7 +3950,7 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha,
 {
        struct qla_hw_data *ha = vha->hw;
        struct qla_tgt *tgt = ha->tgt.qla_tgt;
-       int reason_code;
+       int login_code;
 
        ql_dbg(ql_dbg_tgt, vha, 0xe039,
            "scsi(%ld): ha state %d init_done %d oper_mode %d topo %d\n",
@@ -4003,9 +3993,9 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha,
        {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03b,
                    "qla_target(%d): Async LOOP_UP occured "
-                   "(m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx,
-                   le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
-                   le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
+                   "(m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx,
+                   le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+                   le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
                if (tgt->link_reinit_iocb_pending) {
                        qlt_send_notify_ack(vha, (void *)&tgt->link_reinit_iocb,
                            0, 0, 0, 0, 0, 0);
@@ -4020,23 +4010,24 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha,
        case MBA_RSCN_UPDATE:
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03c,
                    "qla_target(%d): Async event %#x occured "
-                   "(m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx, code,
-                   le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
-                   le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
+                   "(m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx, code,
+                   le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+                   le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
                break;
 
        case MBA_PORT_UPDATE:
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03d,
                    "qla_target(%d): Port update async event %#x "
-                   "occured: updating the ports database (m[1]=%x, m[2]=%x, "
-                   "m[3]=%x, m[4]=%x)", vha->vp_idx, code,
-                   le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
-                   le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
-               reason_code = le16_to_cpu(mailbox[2]);
-               if (reason_code == 0x4)
+                   "occured: updating the ports database (m[0]=%x, m[1]=%x, "
+                   "m[2]=%x, m[3]=%x)", vha->vp_idx, code,
+                   le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+                   le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
+
+               login_code = le16_to_cpu(mailbox[2]);
+               if (login_code == 0x4)
                        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03e,
                            "Async MB 2: Got PLOGI Complete\n");
-               else if (reason_code == 0x7)
+               else if (login_code == 0x7)
                        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03f,
                            "Async MB 2: Port Logged Out\n");
                break;
@@ -4044,9 +4035,9 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha,
        default:
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf040,
                    "qla_target(%d): Async event %#x occured: "
-                   "ignore (m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx,
-                   code, le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
-                   le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4]));
+                   "ignore (m[0]=%x, m[1]=%x, m[2]=%x, m[3]=%x)", vha->vp_idx,
+                   code, le16_to_cpu(mailbox[0]), le16_to_cpu(mailbox[1]),
+                   le16_to_cpu(mailbox[2]), le16_to_cpu(mailbox[3]));
                break;
        }
 
index 9f9ef1644fd97d1fbcb5ba1f978c5080411f9991..170af1571214095fe82db73fa52f520c16a8197b 100644 (file)
@@ -639,7 +639,7 @@ struct qla_tgt_func_tmpl {
 
        int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *,
                        unsigned char *, uint32_t, int, int, int);
-       int (*handle_data)(struct qla_tgt_cmd *);
+       void (*handle_data)(struct qla_tgt_cmd *);
        int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, uint32_t, uint8_t,
                        uint32_t);
        void (*free_cmd)(struct qla_tgt_cmd *);
@@ -813,7 +813,6 @@ struct qla_tgt_sess {
        unsigned int conf_compl_supported:1;
        unsigned int deleted:1;
        unsigned int local:1;
-       unsigned int tearing_down:1;
 
        struct se_session *se_sess;
        struct scsi_qla_host *vha;
index 6e64314dbbb3d33e70782e1506039f9480d1b5c3..4752f65a9272a610a80bb17e25c3ebd736c9894b 100644 (file)
@@ -38,8 +38,6 @@
 #include <linux/string.h>
 #include <linux/configfs.h>
 #include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -466,8 +464,7 @@ static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess)
        vha = sess->vha;
 
        spin_lock_irqsave(&vha->hw->hardware_lock, flags);
-       sess->tearing_down = 1;
-       target_splice_sess_cmd_list(se_sess);
+       target_sess_cmd_list_set_waiting(se_sess);
        spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
 
        return 1;
@@ -600,28 +597,15 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
                return -EINVAL;
        }
 
-       target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0],
+       return target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0],
                                cmd->unpacked_lun, data_length, fcp_task_attr,
                                data_dir, flags);
-       return 0;
 }
 
-static void tcm_qla2xxx_do_rsp(struct work_struct *work)
+static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 {
        struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
-       /*
-        * Dispatch ->queue_status from workqueue process context
-        */
-       transport_generic_request_failure(&cmd->se_cmd);
-}
 
-/*
- * Called from qla_target.c:qlt_do_ctio_completion()
- */
-static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
-{
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-       unsigned long flags;
        /*
         * Ensure that the complete FCP WRITE payload has been received.
         * Otherwise return an exception via CHECK_CONDITION status.
@@ -631,24 +615,26 @@ static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
                 * Check if se_cmd has already been aborted via LUN_RESET, and
                 * waiting upon completion in tcm_qla2xxx_write_pending_status()
                 */
-               spin_lock_irqsave(&se_cmd->t_state_lock, flags);
-               if (se_cmd->transport_state & CMD_T_ABORTED) {
-                       spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
-                       complete(&se_cmd->t_transport_stop_comp);
-                       return 0;
+               if (cmd->se_cmd.transport_state & CMD_T_ABORTED) {
+                       complete(&cmd->se_cmd.t_transport_stop_comp);
+                       return;
                }
-               spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
 
-               se_cmd->scsi_sense_reason = TCM_CHECK_CONDITION_ABORT_CMD;
-               INIT_WORK(&cmd->work, tcm_qla2xxx_do_rsp);
-               queue_work(tcm_qla2xxx_free_wq, &cmd->work);
-               return 0;
+               cmd->se_cmd.scsi_sense_reason = TCM_CHECK_CONDITION_ABORT_CMD;
+               transport_generic_request_failure(&cmd->se_cmd);
+               return;
        }
-       /*
-        * We now tell TCM to queue this WRITE CDB with TRANSPORT_PROCESS_WRITE
-        * status to the backstore processing thread.
-        */
-       return transport_generic_handle_data(&cmd->se_cmd);
+
+       return target_execute_cmd(&cmd->se_cmd);
+}
+
+/*
+ * Called from qla_target.c:qlt_do_ctio_completion()
+ */
+static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd)
+{
+       INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work);
+       queue_work(tcm_qla2xxx_free_wq, &cmd->work);
 }
 
 /*
@@ -1690,7 +1676,6 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
        .tpg_alloc_fabric_acl           = tcm_qla2xxx_alloc_fabric_acl,
        .tpg_release_fabric_acl         = tcm_qla2xxx_release_fabric_acl,
        .tpg_get_inst_index             = tcm_qla2xxx_tpg_get_inst_index,
-       .new_cmd_map                    = NULL,
        .check_stop_free                = tcm_qla2xxx_check_stop_free,
        .release_cmd                    = tcm_qla2xxx_release_cmd,
        .put_session                    = tcm_qla2xxx_put_session,
index ae781487461829ae190f41f52d6f3e267e1fa5bb..0727345388766d22cfbbc9441c92e291a5f8c841 100644 (file)
@@ -22,11 +22,6 @@ static int __init wait_scan_init(void)
         * and might not yet have reached the scsi async scanning
         */
        wait_for_device_probe();
-       /*
-        * and then we wait for the actual asynchronous scsi scan
-        * to finish.
-        */
-       scsi_complete_async_scans();
        return 0;
 }
 
index 972a94c58be3be01315af2f40aad90a067d4643d..646a7657fe62fbb545f95fc771b406d0cad6e5f9 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <mach/dma.h>
 #include <plat/s3c64xx-spi.h>
 
+#define MAX_SPI_PORTS          3
+
 /* Registers and bit-fields */
 
 #define S3C64XX_SPI_CH_CFG             0x00
 #define S3C64XX_SPI_SLAVE_AUTO                 (1<<1)
 #define S3C64XX_SPI_SLAVE_SIG_INACT            (1<<0)
 
-#define S3C64XX_SPI_ACT(c) writel(0, (c)->regs + S3C64XX_SPI_SLAVE_SEL)
-
-#define S3C64XX_SPI_DEACT(c) writel(S3C64XX_SPI_SLAVE_SIG_INACT, \
-                                       (c)->regs + S3C64XX_SPI_SLAVE_SEL)
-
 #define S3C64XX_SPI_INT_TRAILING_EN            (1<<6)
 #define S3C64XX_SPI_INT_RX_OVERRUN_EN          (1<<5)
 #define S3C64XX_SPI_INT_RX_UNDERRUN_EN         (1<<4)
 
 #define S3C64XX_SPI_FBCLK_MSK          (3<<0)
 
-#define S3C64XX_SPI_ST_TRLCNTZ(v, i) ((((v) >> (i)->rx_lvl_offset) & \
-                                       (((i)->fifo_lvl_mask + 1))) \
-                                       ? 1 : 0)
-
-#define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & (1 << (i)->tx_st_done)) ? 1 : 0)
-#define TX_FIFO_LVL(v, i) (((v) >> 6) & (i)->fifo_lvl_mask)
-#define RX_FIFO_LVL(v, i) (((v) >> (i)->rx_lvl_offset) & (i)->fifo_lvl_mask)
+#define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id])
+#define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \
+                               (1 << (i)->port_conf->tx_st_done)) ? 1 : 0)
+#define TX_FIFO_LVL(v, i) (((v) >> 6) & FIFO_LVL_MASK(i))
+#define RX_FIFO_LVL(v, i) (((v) >> (i)->port_conf->rx_lvl_offset) & \
+                                       FIFO_LVL_MASK(i))
 
 #define S3C64XX_SPI_MAX_TRAILCNT       0x3ff
 #define S3C64XX_SPI_TRAILCNT_OFF       19
@@ -135,6 +134,29 @@ struct s3c64xx_spi_dma_data {
        unsigned                ch;
        enum dma_data_direction direction;
        enum dma_ch     dmach;
+       struct property         *dma_prop;
+};
+
+/**
+ * struct s3c64xx_spi_info - SPI Controller hardware info
+ * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register.
+ * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter.
+ * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter.
+ * @high_speed: True, if the controller supports HIGH_SPEED_EN bit.
+ * @clk_from_cmu: True, if the controller does not include a clock mux and
+ *     prescaler unit.
+ *
+ * The Samsung s3c64xx SPI controller are used on various Samsung SoC's but
+ * differ in some aspects such as the size of the fifo and spi bus clock
+ * setup. Such differences are specified to the driver using this structure
+ * which is provided as driver data to the driver.
+ */
+struct s3c64xx_spi_port_config {
+       int     fifo_lvl_mask[MAX_SPI_PORTS];
+       int     rx_lvl_offset;
+       int     tx_st_done;
+       bool    high_speed;
+       bool    clk_from_cmu;
 };
 
 /**
@@ -175,6 +197,9 @@ struct s3c64xx_spi_driver_data {
        struct s3c64xx_spi_dma_data     rx_dma;
        struct s3c64xx_spi_dma_data     tx_dma;
        struct samsung_dma_ops          *ops;
+       struct s3c64xx_spi_port_config  *port_conf;
+       unsigned int                    port_id;
+       unsigned long                   gpios[4];
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -183,7 +208,6 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
 
 static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 {
-       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        unsigned long loops;
        u32 val;
@@ -199,7 +223,7 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
        loops = msecs_to_loops(1);
        do {
                val = readl(regs + S3C64XX_SPI_STATUS);
-       } while (TX_FIFO_LVL(val, sci) && loops--);
+       } while (TX_FIFO_LVL(val, sdd) && loops--);
 
        if (loops == 0)
                dev_warn(&sdd->pdev->dev, "Timed out flushing TX FIFO\n");
@@ -208,7 +232,7 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
        loops = msecs_to_loops(1);
        do {
                val = readl(regs + S3C64XX_SPI_STATUS);
-               if (RX_FIFO_LVL(val, sci))
+               if (RX_FIFO_LVL(val, sdd))
                        readl(regs + S3C64XX_SPI_RX_DATA);
                else
                        break;
@@ -262,14 +286,24 @@ 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 info;
+       struct samsung_dma_prep info;
+       struct samsung_dma_config config;
 
-       if (dma->direction == DMA_DEV_TO_MEM)
+       if (dma->direction == DMA_DEV_TO_MEM) {
                sdd = container_of((void *)dma,
                        struct s3c64xx_spi_driver_data, rx_dma);
-       else
+               config.direction = sdd->rx_dma.direction;
+               config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+               config.width = sdd->cur_bpw / 8;
+               sdd->ops->config(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(sdd->tx_dma.ch, &config);
+       }
 
        info.cap = DMA_SLAVE;
        info.len = len;
@@ -284,20 +318,17 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
 
 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 {
-       struct samsung_dma_info info;
+       struct samsung_dma_req req;
 
        sdd->ops = samsung_dma_get_ops();
 
-       info.cap = DMA_SLAVE;
-       info.client = &s3c64xx_spi_dma_client;
-       info.width = sdd->cur_bpw / 8;
+       req.cap = DMA_SLAVE;
+       req.client = &s3c64xx_spi_dma_client;
 
-       info.direction = sdd->rx_dma.direction;
-       info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
-       sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info);
-       info.direction =  sdd->tx_dma.direction;
-       info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
-       sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info);
+       req.dt_dmach_prop = sdd->rx_dma.dma_prop;
+       sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req);
+       req.dt_dmach_prop = sdd->tx_dma.dma_prop;
+       sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req);
 
        return 1;
 }
@@ -306,7 +337,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                                struct spi_device *spi,
                                struct spi_transfer *xfer, int dma_mode)
 {
-       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        u32 modecfg, chcfg;
 
@@ -356,7 +386,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
        if (xfer->rx_buf != NULL) {
                sdd->state |= RXBUSY;
 
-               if (sci->high_speed && sdd->cur_speed >= 30000000UL
+               if (sdd->port_conf->high_speed && sdd->cur_speed >= 30000000UL
                                        && !(sdd->cur_mode & SPI_CPHA))
                        chcfg |= S3C64XX_SPI_CH_HS_EN;
 
@@ -383,20 +413,19 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
                if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
                        /* Deselect the last toggled device */
                        cs = sdd->tgl_spi->controller_data;
-                       cs->set_level(cs->line,
-                                       spi->mode & SPI_CS_HIGH ? 0 : 1);
+                       gpio_set_value(cs->line,
+                               spi->mode & SPI_CS_HIGH ? 0 : 1);
                }
                sdd->tgl_spi = NULL;
        }
 
        cs = spi->controller_data;
-       cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
+       gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
 }
 
 static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
                                struct spi_transfer *xfer, int dma_mode)
 {
-       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        unsigned long val;
        int ms;
@@ -413,7 +442,7 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
                val = msecs_to_loops(ms);
                do {
                        status = readl(regs + S3C64XX_SPI_STATUS);
-               } while (RX_FIFO_LVL(status, sci) < xfer->len && --val);
+               } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
        }
 
        if (!val)
@@ -432,8 +461,8 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
                if (xfer->rx_buf == NULL) {
                        val = msecs_to_loops(10);
                        status = readl(regs + S3C64XX_SPI_STATUS);
-                       while ((TX_FIFO_LVL(status, sci)
-                               || !S3C64XX_SPI_ST_TX_DONE(status, sci))
+                       while ((TX_FIFO_LVL(status, sdd)
+                               || !S3C64XX_SPI_ST_TX_DONE(status, sdd))
                                        && --val) {
                                cpu_relax();
                                status = readl(regs + S3C64XX_SPI_STATUS);
@@ -477,17 +506,16 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
        if (sdd->tgl_spi == spi)
                sdd->tgl_spi = NULL;
 
-       cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
+       gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
 }
 
 static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 {
-       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        u32 val;
 
        /* Disable Clock */
-       if (sci->clk_from_cmu) {
+       if (sdd->port_conf->clk_from_cmu) {
                clk_disable(sdd->src_clk);
        } else {
                val = readl(regs + S3C64XX_SPI_CLK_CFG);
@@ -531,7 +559,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 
        writel(val, regs + S3C64XX_SPI_MODE_CFG);
 
-       if (sci->clk_from_cmu) {
+       if (sdd->port_conf->clk_from_cmu) {
                /* Configure Clock */
                /* There is half-multiplier before the SPI */
                clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
@@ -557,7 +585,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
                                                struct spi_message *msg)
 {
-       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        struct device *dev = &sdd->pdev->dev;
        struct spi_transfer *xfer;
 
@@ -573,7 +600,7 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
        /* Map until end or first fail */
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
 
-               if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
+               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
                        continue;
 
                if (xfer->tx_buf != NULL) {
@@ -607,7 +634,6 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
 static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
                                                struct spi_message *msg)
 {
-       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        struct device *dev = &sdd->pdev->dev;
        struct spi_transfer *xfer;
 
@@ -616,7 +642,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
 
-               if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
+               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
                        continue;
 
                if (xfer->rx_buf != NULL
@@ -635,7 +661,6 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
                                            struct spi_message *msg)
 {
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        struct spi_device *spi = msg->spi;
        struct s3c64xx_spi_csinfo *cs = spi->controller_data;
        struct spi_transfer *xfer;
@@ -690,7 +715,7 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
                }
 
                /* Polling method for xfers not bigger than FIFO capacity */
-               if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
+               if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
                        use_dma = 0;
                else
                        use_dma = 1;
@@ -707,14 +732,15 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
                enable_cs(sdd, spi);
 
                /* Start the signals */
-               S3C64XX_SPI_ACT(sdd);
+               writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
 
                spin_unlock_irqrestore(&sdd->lock, flags);
 
                status = wait_for_xfer(sdd, xfer, use_dma);
 
                /* Quiese the signals */
-               S3C64XX_SPI_DEACT(sdd);
+               writel(S3C64XX_SPI_SLAVE_SIG_INACT,
+                      sdd->regs + S3C64XX_SPI_SLAVE_SEL);
 
                if (status) {
                        dev_err(&spi->dev, "I/O Error: "
@@ -795,6 +821,48 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
        return 0;
 }
 
+static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
+                               struct s3c64xx_spi_driver_data *sdd,
+                               struct spi_device *spi)
+{
+       struct s3c64xx_spi_csinfo *cs;
+       struct device_node *slave_np, *data_np;
+       u32 fb_delay = 0;
+
+       slave_np = spi->dev.of_node;
+       if (!slave_np) {
+               dev_err(&spi->dev, "device node not found\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       for_each_child_of_node(slave_np, data_np)
+               if (!strcmp(data_np->name, "controller-data"))
+                       break;
+       if (!data_np) {
+               dev_err(&spi->dev, "child node 'controller-data' not found\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       cs = kzalloc(sizeof(*cs), GFP_KERNEL);
+       if (!cs) {
+               dev_err(&spi->dev, "could not allocate memory for controller"
+                                       " data\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
+       if (!gpio_is_valid(cs->line)) {
+               dev_err(&spi->dev, "chip select gpio is not specified or "
+                                       "invalid\n");
+               kfree(cs);
+               return ERR_PTR(-EINVAL);
+       }
+
+       of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
+       cs->fb_delay = fb_delay;
+       return cs;
+}
+
 /*
  * Here we only check the validity of requested configuration
  * and save the configuration in a local data-structure.
@@ -808,14 +876,31 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        struct s3c64xx_spi_info *sci;
        struct spi_message *msg;
        unsigned long flags;
-       int err = 0;
+       int err;
 
-       if (cs == NULL || cs->set_level == NULL) {
+       sdd = spi_master_get_devdata(spi->master);
+       if (!cs && spi->dev.of_node) {
+               cs = s3c64xx_get_slave_ctrldata(sdd, spi);
+               spi->controller_data = cs;
+       }
+
+       if (IS_ERR_OR_NULL(cs)) {
                dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
                return -ENODEV;
        }
 
-       sdd = spi_master_get_devdata(spi->master);
+       if (!spi_get_ctldata(spi)) {
+               err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
+                                      dev_name(&spi->dev));
+               if (err) {
+                       dev_err(&spi->dev,
+                               "Failed to get /CS gpio [%d]: %d\n",
+                               cs->line, err);
+                       goto err_gpio_req;
+               }
+               spi_set_ctldata(spi, cs);
+       }
+
        sci = sdd->cntrlr_info;
 
        spin_lock_irqsave(&sdd->lock, flags);
@@ -826,7 +911,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
                        dev_err(&spi->dev,
                                "setup: attempt while mssg in queue!\n");
                        spin_unlock_irqrestore(&sdd->lock, flags);
-                       return -EBUSY;
+                       err = -EBUSY;
+                       goto err_msgq;
                }
        }
 
@@ -844,7 +930,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        pm_runtime_get_sync(&sdd->pdev->dev);
 
        /* Check if we can provide the requested rate */
-       if (!sci->clk_from_cmu) {
+       if (!sdd->port_conf->clk_from_cmu) {
                u32 psr, speed;
 
                /* Max possible */
@@ -869,22 +955,44 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
                }
 
                speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
-               if (spi->max_speed_hz >= speed)
+               if (spi->max_speed_hz >= speed) {
                        spi->max_speed_hz = speed;
-               else
+               } else {
                        err = -EINVAL;
+                       goto setup_exit;
+               }
        }
 
        pm_runtime_put(&sdd->pdev->dev);
+       disable_cs(sdd, spi);
+       return 0;
 
 setup_exit:
-
        /* setup() returns with device de-selected */
        disable_cs(sdd, spi);
 
+err_msgq:
+       gpio_free(cs->line);
+       spi_set_ctldata(spi, NULL);
+
+err_gpio_req:
+       kfree(cs);
+
        return err;
 }
 
+static void s3c64xx_spi_cleanup(struct spi_device *spi)
+{
+       struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi);
+
+       if (cs) {
+               gpio_free(cs->line);
+               if (spi->dev.of_node)
+                       kfree(cs);
+       }
+       spi_set_ctldata(spi, NULL);
+}
+
 static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
 {
        struct s3c64xx_spi_driver_data *sdd = data;
@@ -920,12 +1028,12 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
 
        sdd->cur_speed = 0;
 
-       S3C64XX_SPI_DEACT(sdd);
+       writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
 
        /* Disable Interrupts - we use Polling if not DMA mode */
        writel(0, regs + S3C64XX_SPI_INT_EN);
 
-       if (!sci->clk_from_cmu)
+       if (!sdd->port_conf->clk_from_cmu)
                writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
                                regs + S3C64XX_SPI_CLK_CFG);
        writel(0, regs + S3C64XX_SPI_MODE_CFG);
@@ -946,40 +1054,165 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
        flush_fifo(sdd);
 }
 
-static int __init s3c64xx_spi_probe(struct platform_device *pdev)
+static int __devinit s3c64xx_spi_get_dmares(
+                       struct s3c64xx_spi_driver_data *sdd, bool tx)
+{
+       struct platform_device *pdev = sdd->pdev;
+       struct s3c64xx_spi_dma_data *dma_data;
+       struct property *prop;
+       struct resource *res;
+       char prop_name[15], *chan_str;
+
+       if (tx) {
+               dma_data = &sdd->tx_dma;
+               dma_data->direction = DMA_TO_DEVICE;
+               chan_str = "tx";
+       } else {
+               dma_data = &sdd->rx_dma;
+               dma_data->direction = DMA_FROM_DEVICE;
+               chan_str = "rx";
+       }
+
+       if (!sdd->pdev->dev.of_node) {
+               res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
+               if (!res) {
+                       dev_err(&pdev->dev, "Unable to get SPI-%s dma "
+                                       "resource\n", chan_str);
+                       return -ENXIO;
+               }
+               dma_data->dmach = res->start;
+               return 0;
+       }
+
+       sprintf(prop_name, "%s-dma-channel", chan_str);
+       prop = of_find_property(pdev->dev.of_node, prop_name, NULL);
+       if (!prop) {
+               dev_err(&pdev->dev, "%s dma channel property not specified\n",
+                                       chan_str);
+               return -ENXIO;
+       }
+
+       dma_data->dmach = DMACH_DT_PROP;
+       dma_data->dma_prop = prop;
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
+{
+       struct device *dev = &sdd->pdev->dev;
+       int idx, gpio, ret;
+
+       /* find gpios for mosi, miso and clock lines */
+       for (idx = 0; idx < 3; idx++) {
+               gpio = of_get_gpio(dev->of_node, idx);
+               if (!gpio_is_valid(gpio)) {
+                       dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio);
+                       goto free_gpio;
+               }
+
+               ret = gpio_request(gpio, "spi-bus");
+               if (ret) {
+                       dev_err(dev, "gpio [%d] request failed: %d\n",
+                               gpio, ret);
+                       goto free_gpio;
+               }
+       }
+       return 0;
+
+free_gpio:
+       while (--idx >= 0)
+               gpio_free(sdd->gpios[idx]);
+       return -EINVAL;
+}
+
+static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
+{
+       unsigned int idx;
+       for (idx = 0; idx < 3; idx++)
+               gpio_free(sdd->gpios[idx]);
+}
+
+static struct __devinit s3c64xx_spi_info * s3c64xx_spi_parse_dt(
+                                               struct device *dev)
 {
-       struct resource *mem_res, *dmatx_res, *dmarx_res;
-       struct s3c64xx_spi_driver_data *sdd;
        struct s3c64xx_spi_info *sci;
-       struct spi_master *master;
-       int ret, irq;
-       char clk_name[16];
+       u32 temp;
 
-       if (pdev->id < 0) {
-               dev_err(&pdev->dev,
-                               "Invalid platform device id-%d\n", pdev->id);
-               return -ENODEV;
+       sci = devm_kzalloc(dev, sizeof(*sci), GFP_KERNEL);
+       if (!sci) {
+               dev_err(dev, "memory allocation for spi_info failed\n");
+               return ERR_PTR(-ENOMEM);
        }
 
-       if (pdev->dev.platform_data == NULL) {
-               dev_err(&pdev->dev, "platform_data missing!\n");
-               return -ENODEV;
+       if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) {
+               dev_warn(dev, "spi bus clock parent not specified, using "
+                               "clock at index 0 as parent\n");
+               sci->src_clk_nr = 0;
+       } else {
+               sci->src_clk_nr = temp;
        }
 
-       sci = pdev->dev.platform_data;
+       if (of_property_read_u32(dev->of_node, "num-cs", &temp)) {
+               dev_warn(dev, "number of chip select lines not specified, "
+                               "assuming 1 chip select line\n");
+               sci->num_cs = 1;
+       } else {
+               sci->num_cs = temp;
+       }
+
+       return sci;
+}
+#else
+static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
+{
+       return dev->platform_data;
+}
+
+static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
+{
+       return -EINVAL;
+}
+
+static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
+{
+}
+#endif
 
-       /* Check for availability of necessary resource */
+static const struct of_device_id s3c64xx_spi_dt_match[];
 
-       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (dmatx_res == NULL) {
-               dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n");
-               return -ENXIO;
+static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
+                                               struct platform_device *pdev)
+{
+#ifdef CONFIG_OF
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(s3c64xx_spi_dt_match, pdev->dev.of_node);
+               return (struct s3c64xx_spi_port_config *)match->data;
        }
+#endif
+       return (struct s3c64xx_spi_port_config *)
+                        platform_get_device_id(pdev)->driver_data;
+}
 
-       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (dmarx_res == NULL) {
-               dev_err(&pdev->dev, "Unable to get SPI-Rx dma resource\n");
-               return -ENXIO;
+static int __init s3c64xx_spi_probe(struct platform_device *pdev)
+{
+       struct resource *mem_res;
+       struct s3c64xx_spi_driver_data *sdd;
+       struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
+       struct spi_master *master;
+       int ret, irq;
+       char clk_name[16];
+
+       if (!sci && pdev->dev.of_node) {
+               sci = s3c64xx_spi_parse_dt(&pdev->dev);
+               if (IS_ERR(sci))
+                       return PTR_ERR(sci);
+       }
+
+       if (!sci) {
+               dev_err(&pdev->dev, "platform_data missing!\n");
+               return -ENODEV;
        }
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1004,19 +1237,37 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, master);
 
        sdd = spi_master_get_devdata(master);
+       sdd->port_conf = s3c64xx_spi_get_port_config(pdev);
        sdd->master = master;
        sdd->cntrlr_info = sci;
        sdd->pdev = pdev;
        sdd->sfr_start = mem_res->start;
-       sdd->tx_dma.dmach = dmatx_res->start;
-       sdd->tx_dma.direction = DMA_MEM_TO_DEV;
-       sdd->rx_dma.dmach = dmarx_res->start;
-       sdd->rx_dma.direction = DMA_DEV_TO_MEM;
+       if (pdev->dev.of_node) {
+               ret = of_alias_get_id(pdev->dev.of_node, "spi");
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "failed to get alias id, "
+                                               "errno %d\n", ret);
+                       goto err0;
+               }
+               sdd->port_id = ret;
+       } else {
+               sdd->port_id = pdev->id;
+       }
 
        sdd->cur_bpw = 8;
 
-       master->bus_num = pdev->id;
+       ret = s3c64xx_spi_get_dmares(sdd, true);
+       if (ret)
+               goto err0;
+
+       ret = s3c64xx_spi_get_dmares(sdd, false);
+       if (ret)
+               goto err0;
+
+       master->dev.of_node = pdev->dev.of_node;
+       master->bus_num = sdd->port_id;
        master->setup = s3c64xx_spi_setup;
+       master->cleanup = s3c64xx_spi_cleanup;
        master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
        master->transfer_one_message = s3c64xx_spi_transfer_one_message;
        master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
@@ -1025,21 +1276,17 @@ static int __init 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;
 
-       if (request_mem_region(mem_res->start,
-                       resource_size(mem_res), pdev->name) == NULL) {
-               dev_err(&pdev->dev, "Req mem region failed\n");
-               ret = -ENXIO;
-               goto err0;
-       }
-
-       sdd->regs = ioremap(mem_res->start, resource_size(mem_res));
+       sdd->regs = devm_request_and_ioremap(&pdev->dev, mem_res);
        if (sdd->regs == NULL) {
                dev_err(&pdev->dev, "Unable to remap IO\n");
                ret = -ENXIO;
                goto err1;
        }
 
-       if (sci->cfg_gpio == NULL || sci->cfg_gpio(pdev)) {
+       if (!sci->cfg_gpio && pdev->dev.of_node) {
+               if (s3c64xx_spi_parse_dt_gpio(sdd))
+                       return -EBUSY;
+       } else if (sci->cfg_gpio == NULL || sci->cfg_gpio()) {
                dev_err(&pdev->dev, "Unable to config gpio\n");
                ret = -EBUSY;
                goto err2;
@@ -1075,7 +1322,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
        }
 
        /* Setup Deufult Mode */
-       s3c64xx_spi_hwinit(sdd, pdev->id);
+       s3c64xx_spi_hwinit(sdd, sdd->port_id);
 
        spin_lock_init(&sdd->lock);
        init_completion(&sdd->xfer_completion);
@@ -1100,7 +1347,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
                                        "with %d Slaves attached\n",
-                                       pdev->id, master->num_chipselect);
+                                       sdd->port_id, master->num_chipselect);
        dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
                                        mem_res->end, mem_res->start,
                                        sdd->rx_dma.dmach, sdd->tx_dma.dmach);
@@ -1120,10 +1367,10 @@ err5:
 err4:
        clk_put(sdd->clk);
 err3:
+       if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
+               s3c64xx_spi_dt_gpio_free(sdd);
 err2:
-       iounmap((void *) sdd->regs);
 err1:
-       release_mem_region(mem_res->start, resource_size(mem_res));
 err0:
        platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
@@ -1135,7 +1382,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
 {
        struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-       struct resource *mem_res;
 
        pm_runtime_disable(&pdev->dev);
 
@@ -1151,11 +1397,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
        clk_disable(sdd->clk);
        clk_put(sdd->clk);
 
-       iounmap((void *) sdd->regs);
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (mem_res != NULL)
-               release_mem_region(mem_res->start, resource_size(mem_res));
+       if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
+               s3c64xx_spi_dt_gpio_free(sdd);
 
        platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
@@ -1175,6 +1418,9 @@ static int s3c64xx_spi_suspend(struct device *dev)
        clk_disable(sdd->src_clk);
        clk_disable(sdd->clk);
 
+       if (!sdd->cntrlr_info->cfg_gpio && dev->of_node)
+               s3c64xx_spi_dt_gpio_free(sdd);
+
        sdd->cur_speed = 0; /* Output Clock is stopped */
 
        return 0;
@@ -1182,18 +1428,20 @@ static int s3c64xx_spi_suspend(struct device *dev)
 
 static int s3c64xx_spi_resume(struct device *dev)
 {
-       struct platform_device *pdev = to_platform_device(dev);
        struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
        struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
 
-       sci->cfg_gpio(pdev);
+       if (!sci->cfg_gpio && dev->of_node)
+               s3c64xx_spi_parse_dt_gpio(sdd);
+       else
+               sci->cfg_gpio();
 
        /* Enable the clock */
        clk_enable(sdd->src_clk);
        clk_enable(sdd->clk);
 
-       s3c64xx_spi_hwinit(sdd, pdev->id);
+       s3c64xx_spi_hwinit(sdd, sdd->port_id);
 
        spi_master_resume(master);
 
@@ -1231,13 +1479,89 @@ static const struct dev_pm_ops s3c64xx_spi_pm = {
                           s3c64xx_spi_runtime_resume, NULL)
 };
 
+struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
+       .fifo_lvl_mask  = { 0x7f },
+       .rx_lvl_offset  = 13,
+       .tx_st_done     = 21,
+       .high_speed     = true,
+};
+
+struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
+       .fifo_lvl_mask  = { 0x7f, 0x7F },
+       .rx_lvl_offset  = 13,
+       .tx_st_done     = 21,
+};
+
+struct s3c64xx_spi_port_config s5p64x0_spi_port_config = {
+       .fifo_lvl_mask  = { 0x1ff, 0x7F },
+       .rx_lvl_offset  = 15,
+       .tx_st_done     = 25,
+};
+
+struct s3c64xx_spi_port_config s5pc100_spi_port_config = {
+       .fifo_lvl_mask  = { 0x7f, 0x7F },
+       .rx_lvl_offset  = 13,
+       .tx_st_done     = 21,
+       .high_speed     = true,
+};
+
+struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
+       .fifo_lvl_mask  = { 0x1ff, 0x7F },
+       .rx_lvl_offset  = 15,
+       .tx_st_done     = 25,
+       .high_speed     = true,
+};
+
+struct s3c64xx_spi_port_config exynos4_spi_port_config = {
+       .fifo_lvl_mask  = { 0x1ff, 0x7F, 0x7F },
+       .rx_lvl_offset  = 15,
+       .tx_st_done     = 25,
+       .high_speed     = true,
+       .clk_from_cmu   = true,
+};
+
+static struct platform_device_id s3c64xx_spi_driver_ids[] = {
+       {
+               .name           = "s3c2443-spi",
+               .driver_data    = (kernel_ulong_t)&s3c2443_spi_port_config,
+       }, {
+               .name           = "s3c6410-spi",
+               .driver_data    = (kernel_ulong_t)&s3c6410_spi_port_config,
+       }, {
+               .name           = "s5p64x0-spi",
+               .driver_data    = (kernel_ulong_t)&s5p64x0_spi_port_config,
+       }, {
+               .name           = "s5pc100-spi",
+               .driver_data    = (kernel_ulong_t)&s5pc100_spi_port_config,
+       }, {
+               .name           = "s5pv210-spi",
+               .driver_data    = (kernel_ulong_t)&s5pv210_spi_port_config,
+       }, {
+               .name           = "exynos4210-spi",
+               .driver_data    = (kernel_ulong_t)&exynos4_spi_port_config,
+       },
+       { },
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id s3c64xx_spi_dt_match[] = {
+       { .compatible = "samsung,exynos4210-spi",
+                       .data = (void *)&exynos4_spi_port_config,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
+#endif /* CONFIG_OF */
+
 static struct platform_driver s3c64xx_spi_driver = {
        .driver = {
                .name   = "s3c64xx-spi",
                .owner = THIS_MODULE,
                .pm = &s3c64xx_spi_pm,
+               .of_match_table = of_match_ptr(s3c64xx_spi_dt_match),
        },
        .remove = s3c64xx_spi_remove,
+       .id_table = s3c64xx_spi_driver_ids,
 };
 MODULE_ALIAS("platform:s3c64xx-spi");
 
index 61648d84fbb6c8eb93c92f7a63a44971cf71415c..9fdcb561422ff844346598d0f3057bf8c3cff439 100644 (file)
@@ -9,7 +9,8 @@ target_core_mod-y               := target_core_configfs.o \
                                   target_core_tmr.o \
                                   target_core_tpg.o \
                                   target_core_transport.o \
-                                  target_core_cdb.o \
+                                  target_core_sbc.o \
+                                  target_core_spc.o \
                                   target_core_ua.o \
                                   target_core_rd.o \
                                   target_core_stat.o
index d57d10cb2e47525406daae44cb22c5c5a8e87937..97c0f78c3c9ca87232fceff82943d293a036d2e1 100644 (file)
@@ -429,19 +429,8 @@ int iscsit_reset_np_thread(
 
 int iscsit_del_np_comm(struct iscsi_np *np)
 {
-       if (!np->np_socket)
-               return 0;
-
-       /*
-        * Some network transports allocate their own struct sock->file,
-        * see  if we need to free any additional allocated resources.
-        */
-       if (np->np_flags & NPF_SCTP_STRUCT_FILE) {
-               kfree(np->np_socket->file);
-               np->np_socket->file = NULL;
-       }
-
-       sock_release(np->np_socket);
+       if (np->np_socket)
+               sock_release(np->np_socket);
        return 0;
 }
 
@@ -1413,8 +1402,10 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
                spin_unlock_bh(&cmd->istate_lock);
 
                iscsit_stop_dataout_timer(cmd);
-               return (!ooo_cmdsn) ? transport_generic_handle_data(
-                                       &cmd->se_cmd) : 0;
+               if (ooo_cmdsn)
+                       return 0;
+               target_execute_cmd(&cmd->se_cmd);
+               return 0;
        } else /* DATAOUT_CANNOT_RECOVER */
                return -1;
 
@@ -2683,7 +2674,7 @@ static int iscsit_send_logout_response(
                 */
                logout_conn = iscsit_get_conn_from_cid_rcfr(sess,
                                cmd->logout_cid);
-               if ((logout_conn)) {
+               if (logout_conn) {
                        iscsit_connection_reinstatement_rcfr(logout_conn);
                        iscsit_dec_conn_usage_count(logout_conn);
                }
@@ -4077,13 +4068,8 @@ int iscsit_close_connection(
        kfree(conn->conn_ops);
        conn->conn_ops = NULL;
 
-       if (conn->sock) {
-               if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) {
-                       kfree(conn->sock->file);
-                       conn->sock->file = NULL;
-               }
+       if (conn->sock)
                sock_release(conn->sock);
-       }
        conn->thread_set = NULL;
 
        pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
index 69dc8e35c03aa24c2b76ed930e4849a14cbea9ac..a7b25e783b58bedf4bceb927015e4642aafc5c63 100644 (file)
@@ -47,28 +47,6 @@ struct lio_target_configfs_attribute {
        ssize_t (*store)(void *, const char *, size_t);
 };
 
-struct iscsi_portal_group *lio_get_tpg_from_tpg_item(
-       struct config_item *item,
-       struct iscsi_tiqn **tiqn_out)
-{
-       struct se_portal_group *se_tpg = container_of(to_config_group(item),
-                                       struct se_portal_group, tpg_group);
-       struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr;
-       int ret;
-
-       if (!tpg) {
-               pr_err("Unable to locate struct iscsi_portal_group "
-                       "pointer\n");
-               return NULL;
-       }
-       ret = iscsit_get_tpg(tpg);
-       if (ret < 0)
-               return NULL;
-
-       *tiqn_out = tpg->tpg_tiqn;
-       return tpg;
-}
-
 /* Start items for lio_target_portal_cit */
 
 static ssize_t lio_target_np_show_sctp(
index 1c70144cdaf176c95ddc8082721dd165c9dbad69..8a908b28d8b2b1455b0cb4c0816131d418912ae8 100644 (file)
@@ -224,7 +224,6 @@ enum iscsi_timer_flags_table {
 /* Used for struct iscsi_np->np_flags */
 enum np_flags_table {
        NPF_IP_NETWORK          = 0x00,
-       NPF_SCTP_STRUCT_FILE    = 0x01 /* Bugfix */
 };
 
 /* Used for struct iscsi_np->np_thread_state */
@@ -481,6 +480,7 @@ struct iscsi_tmr_req {
        bool                    task_reassign:1;
        u32                     ref_cmd_sn;
        u32                     exp_data_sn;
+       struct iscsi_cmd        *ref_cmd;
        struct iscsi_conn_recovery *conn_recovery;
        struct se_tmr_req       *se_tmr_req;
 };
@@ -503,7 +503,6 @@ struct iscsi_conn {
        u16                     local_port;
        int                     net_size;
        u32                     auth_id;
-#define CONNFLAG_SCTP_STRUCT_FILE                      0x01
        u32                     conn_flags;
        /* Used for iscsi_tx_login_rsp() */
        u32                     login_itt;
index ecdd46deeddaf3d6d9aa9ca3acf5ad45274b2c67..3df8a2cef86faab090bcf24dfbc377cc00b32e04 100644 (file)
@@ -965,8 +965,8 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
                if (cmd->immediate_data) {
                        if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
                                spin_unlock_bh(&cmd->istate_lock);
-                               return transport_generic_handle_data(
-                                               &cmd->se_cmd);
+                               target_execute_cmd(&cmd->se_cmd);
+                               return 0;
                        }
                        spin_unlock_bh(&cmd->istate_lock);
 
index a3656c9903a1edffc95a7c0f11f8dee07396c51c..0694d9b1bce6a4e066a7bba1b1ef5f870b4b51d7 100644 (file)
@@ -518,7 +518,7 @@ int iscsi_login_post_auth_non_zero_tsih(
         * initiator and release the new connection.
         */
        conn_ptr = iscsit_get_conn_from_cid_rcfr(sess, cid);
-       if ((conn_ptr)) {
+       if (conn_ptr) {
                pr_err("Connection exists with CID %hu for %s,"
                        " performing connection reinstatement.\n",
                        conn_ptr->cid, sess->sess_ops->InitiatorName);
@@ -539,7 +539,7 @@ int iscsi_login_post_auth_non_zero_tsih(
        if (sess->sess_ops->ErrorRecoveryLevel == 2) {
                cr = iscsit_get_inactive_connection_recovery_entry(
                                sess, cid);
-               if ((cr)) {
+               if (cr) {
                        pr_debug("Performing implicit logout"
                                " for connection recovery on CID: %hu\n",
                                        conn->cid);
@@ -794,22 +794,6 @@ int iscsi_target_setup_login_socket(
                return ret;
        }
        np->np_socket = sock;
-       /*
-        * The SCTP stack needs struct socket->file.
-        */
-       if ((np->np_network_transport == ISCSI_SCTP_TCP) ||
-           (np->np_network_transport == ISCSI_SCTP_UDP)) {
-               if (!sock->file) {
-                       sock->file = kzalloc(sizeof(struct file), GFP_KERNEL);
-                       if (!sock->file) {
-                               pr_err("Unable to allocate struct"
-                                               " file for SCTP\n");
-                               ret = -ENOMEM;
-                               goto fail;
-                       }
-                       np->np_flags |= NPF_SCTP_STRUCT_FILE;
-               }
-       }
        /*
         * Setup the np->np_sockaddr from the passed sockaddr setup
         * in iscsi_target_configfs.c code..
@@ -869,21 +853,15 @@ int iscsi_target_setup_login_socket(
 
 fail:
        np->np_socket = NULL;
-       if (sock) {
-               if (np->np_flags & NPF_SCTP_STRUCT_FILE) {
-                       kfree(sock->file);
-                       sock->file = NULL;
-               }
-
+       if (sock)
                sock_release(sock);
-       }
        return ret;
 }
 
 static int __iscsi_target_login_thread(struct iscsi_np *np)
 {
        u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
-       int err, ret = 0, set_sctp_conn_flag, stop;
+       int err, ret = 0, stop;
        struct iscsi_conn *conn = NULL;
        struct iscsi_login *login;
        struct iscsi_portal_group *tpg = NULL;
@@ -894,7 +872,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        struct sockaddr_in6 sock_in6;
 
        flush_signals(current);
-       set_sctp_conn_flag = 0;
        sock = np->np_socket;
 
        spin_lock_bh(&np->np_thread_lock);
@@ -917,35 +894,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
                spin_unlock_bh(&np->np_thread_lock);
                goto out;
        }
-       /*
-        * The SCTP stack needs struct socket->file.
-        */
-       if ((np->np_network_transport == ISCSI_SCTP_TCP) ||
-           (np->np_network_transport == ISCSI_SCTP_UDP)) {
-               if (!new_sock->file) {
-                       new_sock->file = kzalloc(
-                                       sizeof(struct file), GFP_KERNEL);
-                       if (!new_sock->file) {
-                               pr_err("Unable to allocate struct"
-                                               " file for SCTP\n");
-                               sock_release(new_sock);
-                               /* Get another socket */
-                               return 1;
-                       }
-                       set_sctp_conn_flag = 1;
-               }
-       }
-
        iscsi_start_login_thread_timer(np);
 
        conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
        if (!conn) {
                pr_err("Could not allocate memory for"
                        " new connection\n");
-               if (set_sctp_conn_flag) {
-                       kfree(new_sock->file);
-                       new_sock->file = NULL;
-               }
                sock_release(new_sock);
                /* Get another socket */
                return 1;
@@ -955,9 +909,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        conn->conn_state = TARG_CONN_STATE_FREE;
        conn->sock = new_sock;
 
-       if (set_sctp_conn_flag)
-               conn->conn_flags |= CONNFLAG_SCTP_STRUCT_FILE;
-
        pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
        conn->conn_state = TARG_CONN_STATE_XPT_UP;
 
@@ -1081,7 +1032,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
                goto new_sess_out;
 
        zero_tsih = (pdu->tsih == 0x0000);
-       if ((zero_tsih)) {
+       if (zero_tsih) {
                /*
                 * This is the leading connection of a new session.
                 * We wait until after authentication to check for
@@ -1205,13 +1156,8 @@ old_sess_out:
                iscsi_release_param_list(conn->param_list);
                conn->param_list = NULL;
        }
-       if (conn->sock) {
-               if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) {
-                       kfree(conn->sock->file);
-                       conn->sock->file = NULL;
-               }
+       if (conn->sock)
                sock_release(conn->sock);
-       }
        kfree(conn);
 
        if (tpg) {
index ed5241e7f12a1c0ced7f5c4c4c9ce30e1c4fd755..0c4760fabfc0f63f753d921ebb60ba2fe1ad3e18 100644 (file)
@@ -681,7 +681,7 @@ int iscsi_update_param_value(struct iscsi_param *param, char *value)
        param->value = kzalloc(strlen(value) + 1, GFP_KERNEL);
        if (!param->value) {
                pr_err("Unable to allocate memory for value.\n");
-               return -1;
+               return -ENOMEM;
        }
 
        memcpy(param->value, value, strlen(value));
index f4e640b51fd103bc8856b310456567d921dbfc0d..f62fe123d902cd78f0bdbee14337564559ec8ec9 100644 (file)
@@ -19,6 +19,7 @@
  ******************************************************************************/
 
 #include <asm/unaligned.h>
+#include <scsi/scsi_device.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
@@ -61,7 +62,7 @@ u8 iscsit_tmr_abort_task(
        }
 
        se_tmr->ref_task_tag            = hdr->rtt;
-       se_tmr->ref_cmd                 = &ref_cmd->se_cmd;
+       tmr_req->ref_cmd                = ref_cmd;
        tmr_req->ref_cmd_sn             = hdr->refcmdsn;
        tmr_req->exp_data_sn            = hdr->exp_datasn;
 
@@ -121,7 +122,7 @@ u8 iscsit_tmr_task_reassign(
        struct iscsi_tmr_req *tmr_req = cmd->tmr_req;
        struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
        struct iscsi_tm *hdr = (struct iscsi_tm *) buf;
-       int ret;
+       int ret, ref_lun;
 
        pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x,"
                " RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n",
@@ -155,9 +156,16 @@ u8 iscsit_tmr_task_reassign(
                return ISCSI_TMF_RSP_REJECTED;
        }
 
+       ref_lun = scsilun_to_int(&hdr->lun);
+       if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) {
+               pr_err("Unable to perform connection recovery for"
+                       " differing ref_lun: %d ref_cmd orig_fe_lun: %u\n",
+                       ref_lun, ref_cmd->se_cmd.orig_fe_lun);
+               return ISCSI_TMF_RSP_REJECTED;
+       }
+
        se_tmr->ref_task_tag            = hdr->rtt;
-       se_tmr->ref_cmd                 = &ref_cmd->se_cmd;
-       se_tmr->ref_task_lun            = get_unaligned_le64(&hdr->lun);
+       tmr_req->ref_cmd                = ref_cmd;
        tmr_req->ref_cmd_sn             = hdr->refcmdsn;
        tmr_req->exp_data_sn            = hdr->exp_datasn;
        tmr_req->conn_recovery          = cr;
@@ -191,9 +199,7 @@ static int iscsit_task_reassign_complete_nop_out(
        struct iscsi_tmr_req *tmr_req,
        struct iscsi_conn *conn)
 {
-       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-       struct se_cmd *se_cmd = se_tmr->ref_cmd;
-       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       struct iscsi_cmd *cmd = tmr_req->ref_cmd;
        struct iscsi_conn_recovery *cr;
 
        if (!cmd->cr) {
@@ -251,7 +257,8 @@ static int iscsit_task_reassign_complete_write(
                        pr_debug("WRITE ITT: 0x%08x: t_state: %d"
                                " never sent to transport\n",
                                cmd->init_task_tag, cmd->se_cmd.t_state);
-                       return transport_generic_handle_data(se_cmd);
+                       target_execute_cmd(se_cmd);
+                       return 0;
                }
 
                cmd->i_state = ISTATE_SEND_STATUS;
@@ -360,9 +367,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd(
        struct iscsi_tmr_req *tmr_req,
        struct iscsi_conn *conn)
 {
-       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-       struct se_cmd *se_cmd = se_tmr->ref_cmd;
-       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       struct iscsi_cmd *cmd = tmr_req->ref_cmd;
        struct iscsi_conn_recovery *cr;
 
        if (!cmd->cr) {
@@ -385,7 +390,7 @@ static int iscsit_task_reassign_complete_scsi_cmnd(
        list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
        spin_unlock_bh(&conn->cmd_lock);
 
-       if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+       if (cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
                cmd->i_state = ISTATE_SEND_STATUS;
                iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
                return 0;
@@ -411,17 +416,14 @@ static int iscsit_task_reassign_complete(
        struct iscsi_tmr_req *tmr_req,
        struct iscsi_conn *conn)
 {
-       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-       struct se_cmd *se_cmd;
        struct iscsi_cmd *cmd;
        int ret = 0;
 
-       if (!se_tmr->ref_cmd) {
+       if (!tmr_req->ref_cmd) {
                pr_err("TMR Request is missing a RefCmd struct iscsi_cmd.\n");
                return -1;
        }
-       se_cmd = se_tmr->ref_cmd;
-       cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       cmd = tmr_req->ref_cmd;
 
        cmd->conn = conn;
 
@@ -547,9 +549,7 @@ int iscsit_task_reassign_prepare_write(
        struct iscsi_tmr_req *tmr_req,
        struct iscsi_conn *conn)
 {
-       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-       struct se_cmd *se_cmd = se_tmr->ref_cmd;
-       struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       struct iscsi_cmd *cmd = tmr_req->ref_cmd;
        struct iscsi_pdu *pdu = NULL;
        struct iscsi_r2t *r2t = NULL, *r2t_tmp;
        int first_incomplete_r2t = 1, i = 0;
@@ -782,14 +782,12 @@ int iscsit_check_task_reassign_expdatasn(
        struct iscsi_tmr_req *tmr_req,
        struct iscsi_conn *conn)
 {
-       struct se_tmr_req *se_tmr = tmr_req->se_tmr_req;
-       struct se_cmd *se_cmd = se_tmr->ref_cmd;
-       struct iscsi_cmd *ref_cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+       struct iscsi_cmd *ref_cmd = tmr_req->ref_cmd;
 
        if (ref_cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD)
                return 0;
 
-       if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION)
+       if (ref_cmd->se_cmd.se_cmd_flags & SCF_SENT_CHECK_CONDITION)
                return 0;
 
        if (ref_cmd->data_direction == DMA_NONE)
index 879d8d0fa3feb38e061c911887e50a91a286c30f..a38a3f8ab0d9236598b3bb7f176443c19334e7de 100644 (file)
@@ -303,6 +303,7 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
 {
        struct iscsi_param *param;
        struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
+       int ret;
 
        spin_lock(&tpg->tpg_state_lock);
        if (tpg->tpg_state == TPG_STATE_ACTIVE) {
@@ -319,19 +320,19 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
        param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list);
        if (!param) {
                spin_unlock(&tpg->tpg_state_lock);
-               return -ENOMEM;
+               return -EINVAL;
        }
 
        if (ISCSI_TPG_ATTRIB(tpg)->authentication) {
-               if (!strcmp(param->value, NONE))
-                       if (iscsi_update_param_value(param, CHAP) < 0) {
-                               spin_unlock(&tpg->tpg_state_lock);
-                               return -ENOMEM;
-                       }
-               if (iscsit_ta_authentication(tpg, 1) < 0) {
-                       spin_unlock(&tpg->tpg_state_lock);
-                       return -ENOMEM;
+               if (!strcmp(param->value, NONE)) {
+                       ret = iscsi_update_param_value(param, CHAP);
+                       if (ret)
+                               goto err;
                }
+
+               ret = iscsit_ta_authentication(tpg, 1);
+               if (ret < 0)
+                       goto err;
        }
 
        tpg->tpg_state = TPG_STATE_ACTIVE;
@@ -344,6 +345,10 @@ int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg)
        spin_unlock(&tiqn->tiqn_tpg_lock);
 
        return 0;
+
+err:
+       spin_unlock(&tpg->tpg_state_lock);
+       return ret;
 }
 
 int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force)
@@ -558,7 +563,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication)
        if ((authentication != 1) && (authentication != 0)) {
                pr_err("Illegal value for authentication parameter:"
                        " %u, ignoring request.\n", authentication);
-               return -1;
+               return -EINVAL;
        }
 
        memset(buf1, 0, sizeof(buf1));
@@ -593,7 +598,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication)
        } else {
                snprintf(buf1, sizeof(buf1), "%s", param->value);
                none = strstr(buf1, NONE);
-               if ((none))
+               if (none)
                        goto out;
                strncat(buf1, ",", strlen(","));
                strncat(buf1, NONE, strlen(NONE));
index 38dfac2b0a1cf1ee91602ab896d4cb271d52195a..5491c632a15ed9073fb1b02efdf6b3ac095c57f8 100644 (file)
@@ -211,12 +211,11 @@ static void tcm_loop_submission_work(struct work_struct *work)
        /*
         * Because some userspace code via scsi-generic do not memset their
         * associated read buffers, go ahead and do that here for type
-        * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
-        * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
-        * by target core in target_setup_cmd_from_cdb() ->
-        * transport_generic_cmd_sequencer().
+        * non-data CDBs.  Also note that this is currently guaranteed to be a
+        * single SGL for this case by target core in
+        * target_setup_cmd_from_cdb() -> transport_generic_cmd_sequencer().
         */
-       if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
+       if (!(se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
            se_cmd->data_direction == DMA_FROM_DEVICE) {
                struct scatterlist *sg = scsi_sglist(sc);
                unsigned char *buf = kmap(sg_page(sg)) + sg->offset;
@@ -779,7 +778,7 @@ static int tcm_loop_write_pending(struct se_cmd *se_cmd)
         * We now tell TCM to add this WRITE CDB directly into the TCM storage
         * object execution queue.
         */
-       transport_generic_process_write(se_cmd);
+       target_execute_cmd(se_cmd);
        return 0;
 }
 
index 7e6136e2ce81dc256babc191fab05953aabf6bfc..39ddba584b30e9d08950bd3143c257da20c80b55 100644 (file)
@@ -1219,28 +1219,14 @@ static void sbp_handle_command(struct sbp_target_request *req)
        ret = sbp_fetch_command(req);
        if (ret) {
                pr_debug("sbp_handle_command: fetch command failed: %d\n", ret);
-               req->status.status |= cpu_to_be32(
-                       STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
-                       STATUS_BLOCK_DEAD(0) |
-                       STATUS_BLOCK_LEN(1) |
-                       STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
-               sbp_send_status(req);
-               sbp_free_request(req);
-               return;
+               goto err;
        }
 
        ret = sbp_fetch_page_table(req);
        if (ret) {
                pr_debug("sbp_handle_command: fetch page table failed: %d\n",
                        ret);
-               req->status.status |= cpu_to_be32(
-                       STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
-                       STATUS_BLOCK_DEAD(0) |
-                       STATUS_BLOCK_LEN(1) |
-                       STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
-               sbp_send_status(req);
-               sbp_free_request(req);
-               return;
+               goto err;
        }
 
        unpacked_lun = req->login->lun->unpacked_lun;
@@ -1249,9 +1235,21 @@ static void sbp_handle_command(struct sbp_target_request *req)
        pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n",
                        req->orb_pointer, unpacked_lun, data_length, data_dir);
 
-       target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
-                       req->sense_buf, unpacked_lun, data_length,
-                       MSG_SIMPLE_TAG, data_dir, 0);
+       if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
+                             req->sense_buf, unpacked_lun, data_length,
+                             MSG_SIMPLE_TAG, data_dir, 0))
+               goto err;
+
+       return;
+
+err:
+       req->status.status |= cpu_to_be32(
+               STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+               STATUS_BLOCK_DEAD(0) |
+               STATUS_BLOCK_LEN(1) |
+               STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+       sbp_send_status(req);
+       sbp_free_request(req);
 }
 
 /*
@@ -1784,8 +1782,7 @@ static int sbp_write_pending(struct se_cmd *se_cmd)
                return ret;
        }
 
-       transport_generic_process_write(se_cmd);
-
+       target_execute_cmd(se_cmd);
        return 0;
 }
 
index 5ad972856a8d58ccb25b763a07239a39a12a57ed..cf2c66f3c11690c81ca23e9fd2ce286e76b56e62 100644 (file)
@@ -300,8 +300,8 @@ int core_free_device_list_for_node(
                lun = deve->se_lun;
 
                spin_unlock_irq(&nacl->device_list_lock);
-               core_update_device_list_for_node(lun, NULL, deve->mapped_lun,
-                       TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+               core_disable_device_list_for_node(lun, NULL, deve->mapped_lun,
+                       TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg);
                spin_lock_irq(&nacl->device_list_lock);
        }
        spin_unlock_irq(&nacl->device_list_lock);
@@ -342,72 +342,46 @@ void core_update_device_list_access(
        spin_unlock_irq(&nacl->device_list_lock);
 }
 
-/*      core_update_device_list_for_node():
+/*      core_enable_device_list_for_node():
  *
  *
  */
-int core_update_device_list_for_node(
+int core_enable_device_list_for_node(
        struct se_lun *lun,
        struct se_lun_acl *lun_acl,
        u32 mapped_lun,
        u32 lun_access,
        struct se_node_acl *nacl,
-       struct se_portal_group *tpg,
-       int enable)
+       struct se_portal_group *tpg)
 {
        struct se_port *port = lun->lun_sep;
-       struct se_dev_entry *deve = nacl->device_list[mapped_lun];
-       int trans = 0;
-       /*
-        * If the MappedLUN entry is being disabled, the entry in
-        * port->sep_alua_list must be removed now before clearing the
-        * struct se_dev_entry pointers below as logic in
-        * core_alua_do_transition_tg_pt() depends on these being present.
-        */
-       if (!enable) {
-               /*
-                * deve->se_lun_acl will be NULL for demo-mode created LUNs
-                * that have not been explicitly concerted to MappedLUNs ->
-                * struct se_lun_acl, but we remove deve->alua_port_list from
-                * port->sep_alua_list. This also means that active UAs and
-                * NodeACL context specific PR metadata for demo-mode
-                * MappedLUN *deve will be released below..
-                */
-               spin_lock_bh(&port->sep_alua_lock);
-               list_del(&deve->alua_port_list);
-               spin_unlock_bh(&port->sep_alua_lock);
-       }
+       struct se_dev_entry *deve;
 
        spin_lock_irq(&nacl->device_list_lock);
-       if (enable) {
-               /*
-                * Check if the call is handling demo mode -> explict LUN ACL
-                * transition.  This transition must be for the same struct se_lun
-                * + mapped_lun that was setup in demo mode..
-                */
-               if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
-                       if (deve->se_lun_acl != NULL) {
-                               pr_err("struct se_dev_entry->se_lun_acl"
-                                       " already set for demo mode -> explict"
-                                       " LUN ACL transition\n");
-                               spin_unlock_irq(&nacl->device_list_lock);
-                               return -EINVAL;
-                       }
-                       if (deve->se_lun != lun) {
-                               pr_err("struct se_dev_entry->se_lun does"
-                                       " match passed struct se_lun for demo mode"
-                                       " -> explict LUN ACL transition\n");
-                               spin_unlock_irq(&nacl->device_list_lock);
-                               return -EINVAL;
-                       }
-                       deve->se_lun_acl = lun_acl;
-                       trans = 1;
-               } else {
-                       deve->se_lun = lun;
-                       deve->se_lun_acl = lun_acl;
-                       deve->mapped_lun = mapped_lun;
-                       deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS;
+
+       deve = nacl->device_list[mapped_lun];
+
+       /*
+        * Check if the call is handling demo mode -> explict LUN ACL
+        * transition.  This transition must be for the same struct se_lun
+        * + mapped_lun that was setup in demo mode..
+        */
+       if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
+               if (deve->se_lun_acl != NULL) {
+                       pr_err("struct se_dev_entry->se_lun_acl"
+                              " already set for demo mode -> explict"
+                              " LUN ACL transition\n");
+                       spin_unlock_irq(&nacl->device_list_lock);
+                       return -EINVAL;
                }
+               if (deve->se_lun != lun) {
+                       pr_err("struct se_dev_entry->se_lun does"
+                              " match passed struct se_lun for demo mode"
+                              " -> explict LUN ACL transition\n");
+                       spin_unlock_irq(&nacl->device_list_lock);
+                       return -EINVAL;
+               }
+               deve->se_lun_acl = lun_acl;
 
                if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) {
                        deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY;
@@ -417,27 +391,72 @@ int core_update_device_list_for_node(
                        deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY;
                }
 
-               if (trans) {
-                       spin_unlock_irq(&nacl->device_list_lock);
-                       return 0;
-               }
-               deve->creation_time = get_jiffies_64();
-               deve->attach_count++;
                spin_unlock_irq(&nacl->device_list_lock);
+               return 0;
+       }
 
-               spin_lock_bh(&port->sep_alua_lock);
-               list_add_tail(&deve->alua_port_list, &port->sep_alua_list);
-               spin_unlock_bh(&port->sep_alua_lock);
+       deve->se_lun = lun;
+       deve->se_lun_acl = lun_acl;
+       deve->mapped_lun = mapped_lun;
+       deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS;
 
-               return 0;
+       if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) {
+               deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY;
+               deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE;
+       } else {
+               deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE;
+               deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY;
        }
+
+       deve->creation_time = get_jiffies_64();
+       deve->attach_count++;
+       spin_unlock_irq(&nacl->device_list_lock);
+
+       spin_lock_bh(&port->sep_alua_lock);
+       list_add_tail(&deve->alua_port_list, &port->sep_alua_list);
+       spin_unlock_bh(&port->sep_alua_lock);
+
+       return 0;
+}
+
+/*      core_disable_device_list_for_node():
+ *
+ *
+ */
+int core_disable_device_list_for_node(
+       struct se_lun *lun,
+       struct se_lun_acl *lun_acl,
+       u32 mapped_lun,
+       u32 lun_access,
+       struct se_node_acl *nacl,
+       struct se_portal_group *tpg)
+{
+       struct se_port *port = lun->lun_sep;
+       struct se_dev_entry *deve = nacl->device_list[mapped_lun];
+
+       /*
+        * If the MappedLUN entry is being disabled, the entry in
+        * port->sep_alua_list must be removed now before clearing the
+        * struct se_dev_entry pointers below as logic in
+        * core_alua_do_transition_tg_pt() depends on these being present.
+        *
+        * deve->se_lun_acl will be NULL for demo-mode created LUNs
+        * that have not been explicitly converted to MappedLUNs ->
+        * struct se_lun_acl, but we remove deve->alua_port_list from
+        * port->sep_alua_list. This also means that active UAs and
+        * NodeACL context specific PR metadata for demo-mode
+        * MappedLUN *deve will be released below..
+        */
+       spin_lock_bh(&port->sep_alua_lock);
+       list_del(&deve->alua_port_list);
+       spin_unlock_bh(&port->sep_alua_lock);
        /*
         * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE
         * PR operation to complete.
         */
-       spin_unlock_irq(&nacl->device_list_lock);
        while (atomic_read(&deve->pr_ref_count) != 0)
                cpu_relax();
+
        spin_lock_irq(&nacl->device_list_lock);
        /*
         * Disable struct se_dev_entry LUN ACL mapping
@@ -475,9 +494,9 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg)
                                continue;
                        spin_unlock_irq(&nacl->device_list_lock);
 
-                       core_update_device_list_for_node(lun, NULL,
+                       core_disable_device_list_for_node(lun, NULL,
                                deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS,
-                               nacl, tpg, 0);
+                               nacl, tpg);
 
                        spin_lock_irq(&nacl->device_list_lock);
                }
@@ -715,7 +734,7 @@ void se_release_device_for_hba(struct se_device *dev)
                se_dev_stop(dev);
 
        if (dev->dev_ptr) {
-               kthread_stop(dev->process_thread);
+               destroy_workqueue(dev->tmr_wq);
                if (dev->transport->free_device)
                        dev->transport->free_device(dev->dev_ptr);
        }
@@ -822,7 +841,7 @@ int se_dev_check_shutdown(struct se_device *dev)
        return ret;
 }
 
-u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
+static u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
 {
        u32 tmp, aligned_max_sectors;
        /*
@@ -1273,7 +1292,6 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size)
 
 struct se_lun *core_dev_add_lun(
        struct se_portal_group *tpg,
-       struct se_hba *hba,
        struct se_device *dev,
        u32 lun)
 {
@@ -1298,7 +1316,7 @@ struct se_lun *core_dev_add_lun(
        pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from"
                " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(),
                tpg->se_tpg_tfo->tpg_get_tag(tpg), lun_p->unpacked_lun,
-               tpg->se_tpg_tfo->get_fabric_name(), hba->hba_id);
+               tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id);
        /*
         * Update LUN maps for dynamically added initiators when
         * generate_node_acl is enabled.
@@ -1470,8 +1488,8 @@ int core_dev_add_initiator_node_lun_acl(
 
        lacl->se_lun = lun;
 
-       if (core_update_device_list_for_node(lun, lacl, lacl->mapped_lun,
-                       lun_access, nacl, tpg, 1) < 0)
+       if (core_enable_device_list_for_node(lun, lacl, lacl->mapped_lun,
+                       lun_access, nacl, tpg) < 0)
                return -EINVAL;
 
        spin_lock(&lun->lun_acl_lock);
@@ -1514,8 +1532,8 @@ int core_dev_del_initiator_node_lun_acl(
        smp_mb__after_atomic_dec();
        spin_unlock(&lun->lun_acl_lock);
 
-       core_update_device_list_for_node(lun, NULL, lacl->mapped_lun,
-               TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+       core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun,
+               TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg);
 
        lacl->se_lun = NULL;
 
index 405cc98eaed6a73b11f5c55d6424e47b1637683e..ea479e54f5fdf3f613cfd2056dc8994b9934c4c0 100644 (file)
@@ -764,8 +764,7 @@ static int target_fabric_port_link(
                goto out;
        }
 
-       lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev,
-                               lun->unpacked_lun);
+       lun_p = core_dev_add_lun(se_tpg, dev, lun->unpacked_lun);
        if (IS_ERR(lun_p)) {
                pr_err("core_dev_add_lun() failed\n");
                ret = PTR_ERR(lun_p);
index 9f99d0404908fd04fe4a68e30c00b3e015f48879..9e2100551c789f70b033e420d0840b1f2e340f5d 100644 (file)
@@ -331,7 +331,7 @@ static int fd_do_writev(struct se_cmd *cmd, struct scatterlist *sgl,
        return 1;
 }
 
-static void fd_emulate_sync_cache(struct se_cmd *cmd)
+static int fd_execute_sync_cache(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct fd_dev *fd_dev = dev->dev_ptr;
@@ -365,7 +365,7 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd)
                pr_err("FILEIO: vfs_fsync_range() failed: %d\n", ret);
 
        if (immed)
-               return;
+               return 0;
 
        if (ret) {
                cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -373,11 +373,15 @@ static void fd_emulate_sync_cache(struct se_cmd *cmd)
        } else {
                target_complete_cmd(cmd, SAM_STAT_GOOD);
        }
+
+       return 0;
 }
 
-static int fd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-               u32 sgl_nents, enum dma_data_direction data_direction)
+static int fd_execute_rw(struct se_cmd *cmd)
 {
+       struct scatterlist *sgl = cmd->t_data_sg;
+       u32 sgl_nents = cmd->t_data_nents;
+       enum dma_data_direction data_direction = cmd->data_direction;
        struct se_device *dev = cmd->se_dev;
        int ret = 0;
 
@@ -550,6 +554,16 @@ static sector_t fd_get_blocks(struct se_device *dev)
        return div_u64(dev_size, dev->se_sub_dev->se_dev_attrib.block_size);
 }
 
+static struct spc_ops fd_spc_ops = {
+       .execute_rw             = fd_execute_rw,
+       .execute_sync_cache     = fd_execute_sync_cache,
+};
+
+static int fd_parse_cdb(struct se_cmd *cmd)
+{
+       return sbc_parse_cdb(cmd, &fd_spc_ops);
+}
+
 static struct se_subsystem_api fileio_template = {
        .name                   = "fileio",
        .owner                  = THIS_MODULE,
@@ -561,8 +575,7 @@ static struct se_subsystem_api fileio_template = {
        .allocate_virtdevice    = fd_allocate_virtdevice,
        .create_virtdevice      = fd_create_virtdevice,
        .free_device            = fd_free_device,
-       .execute_cmd            = fd_execute_cmd,
-       .do_sync_cache          = fd_emulate_sync_cache,
+       .parse_cdb              = fd_parse_cdb,
        .check_configfs_dev_params = fd_check_configfs_dev_params,
        .set_configfs_dev_params = fd_set_configfs_dev_params,
        .show_configfs_dev_params = fd_show_configfs_dev_params,
index fd47950727b4b2ff50edc74ca0c69c23ff35255a..76db75e836ede701c2aed6090a212fdf1a08ad10 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/module.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
+#include <asm/unaligned.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
@@ -96,6 +97,7 @@ static struct se_device *iblock_create_virtdevice(
        struct request_queue *q;
        struct queue_limits *limits;
        u32 dev_flags = 0;
+       fmode_t mode;
        int ret = -EINVAL;
 
        if (!ib_dev) {
@@ -117,8 +119,11 @@ static struct se_device *iblock_create_virtdevice(
        pr_debug( "IBLOCK: Claiming struct block_device: %s\n",
                        ib_dev->ibd_udev_path);
 
-       bd = blkdev_get_by_path(ib_dev->ibd_udev_path,
-                               FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev);
+       mode = FMODE_READ|FMODE_EXCL;
+       if (!ib_dev->ibd_readonly)
+               mode |= FMODE_WRITE;
+
+       bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev);
        if (IS_ERR(bd)) {
                ret = PTR_ERR(bd);
                goto failed;
@@ -292,7 +297,7 @@ static void iblock_end_io_flush(struct bio *bio, int err)
  * Implement SYCHRONIZE CACHE.  Note that we can't handle lba ranges and must
  * always flush the whole cache.
  */
-static void iblock_emulate_sync_cache(struct se_cmd *cmd)
+static int iblock_execute_sync_cache(struct se_cmd *cmd)
 {
        struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
        int immed = (cmd->t_task_cdb[1] & 0x2);
@@ -311,23 +316,98 @@ static void iblock_emulate_sync_cache(struct se_cmd *cmd)
        if (!immed)
                bio->bi_private = cmd;
        submit_bio(WRITE_FLUSH, bio);
+       return 0;
 }
 
-static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
+static int iblock_execute_unmap(struct se_cmd *cmd)
 {
+       struct se_device *dev = cmd->se_dev;
        struct iblock_dev *ibd = dev->dev_ptr;
-       struct block_device *bd = ibd->ibd_bd;
-       int barrier = 0;
+       unsigned char *buf, *ptr = NULL;
+       sector_t lba;
+       int size = cmd->data_length;
+       u32 range;
+       int ret = 0;
+       int dl, bd_dl;
+
+       buf = transport_kmap_data_sg(cmd);
+
+       dl = get_unaligned_be16(&buf[0]);
+       bd_dl = get_unaligned_be16(&buf[2]);
+
+       size = min(size - 8, bd_dl);
+       if (size / 16 > dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) {
+               cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* First UNMAP block descriptor starts at 8 byte offset */
+       ptr = &buf[8];
+       pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
+               " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
+
+       while (size >= 16) {
+               lba = get_unaligned_be64(&ptr[0]);
+               range = get_unaligned_be32(&ptr[8]);
+               pr_debug("UNMAP: Using lba: %llu and range: %u\n",
+                                (unsigned long long)lba, range);
+
+               if (range > dev->se_sub_dev->se_dev_attrib.max_unmap_lba_count) {
+                       cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               if (lba + range > dev->transport->get_blocks(dev) + 1) {
+                       cmd->scsi_sense_reason = TCM_ADDRESS_OUT_OF_RANGE;
+                       ret = -EINVAL;
+                       goto err;
+               }
 
-       return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier);
+               ret = blkdev_issue_discard(ibd->ibd_bd, lba, range,
+                                          GFP_KERNEL, 0);
+               if (ret < 0) {
+                       pr_err("blkdev_issue_discard() failed: %d\n",
+                                       ret);
+                       goto err;
+               }
+
+               ptr += 16;
+               size -= 16;
+       }
+
+err:
+       transport_kunmap_data_sg(cmd);
+       if (!ret)
+               target_complete_cmd(cmd, GOOD);
+       return ret;
+}
+
+static int iblock_execute_write_same(struct se_cmd *cmd)
+{
+       struct iblock_dev *ibd = cmd->se_dev->dev_ptr;
+       int ret;
+
+       ret = blkdev_issue_discard(ibd->ibd_bd, cmd->t_task_lba,
+                                  spc_get_write_same_sectors(cmd), GFP_KERNEL,
+                                  0);
+       if (ret < 0) {
+               pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n");
+               return ret;
+       }
+
+       target_complete_cmd(cmd, GOOD);
+       return 0;
 }
 
 enum {
-       Opt_udev_path, Opt_force, Opt_err
+       Opt_udev_path, Opt_readonly, Opt_force, Opt_err
 };
 
 static match_table_t tokens = {
        {Opt_udev_path, "udev_path=%s"},
+       {Opt_readonly, "readonly=%d"},
        {Opt_force, "force=%d"},
        {Opt_err, NULL}
 };
@@ -340,6 +420,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
        char *orig, *ptr, *arg_p, *opts;
        substring_t args[MAX_OPT_ARGS];
        int ret = 0, token;
+       unsigned long tmp_readonly;
 
        opts = kstrdup(page, GFP_KERNEL);
        if (!opts)
@@ -372,6 +453,22 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
                                        ib_dev->ibd_udev_path);
                        ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH;
                        break;
+               case Opt_readonly:
+                       arg_p = match_strdup(&args[0]);
+                       if (!arg_p) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+                       ret = strict_strtoul(arg_p, 0, &tmp_readonly);
+                       kfree(arg_p);
+                       if (ret < 0) {
+                               pr_err("strict_strtoul() failed for"
+                                               " readonly=\n");
+                               goto out;
+                       }
+                       ib_dev->ibd_readonly = tmp_readonly;
+                       pr_debug("IBLOCK: readonly: %d\n", ib_dev->ibd_readonly);
+                       break;
                case Opt_force:
                        break;
                default:
@@ -411,11 +508,10 @@ static ssize_t iblock_show_configfs_dev_params(
        if (bd)
                bl += sprintf(b + bl, "iBlock device: %s",
                                bdevname(bd, buf));
-       if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) {
-               bl += sprintf(b + bl, "  UDEV PATH: %s\n",
+       if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH)
+               bl += sprintf(b + bl, "  UDEV PATH: %s",
                                ibd->ibd_udev_path);
-       } else
-               bl += sprintf(b + bl, "\n");
+       bl += sprintf(b + bl, "  readonly: %d\n", ibd->ibd_readonly);
 
        bl += sprintf(b + bl, "        ");
        if (bd) {
@@ -493,9 +589,11 @@ static void iblock_submit_bios(struct bio_list *list, int rw)
        blk_finish_plug(&plug);
 }
 
-static int iblock_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-               u32 sgl_nents, enum dma_data_direction data_direction)
+static int iblock_execute_rw(struct se_cmd *cmd)
 {
+       struct scatterlist *sgl = cmd->t_data_sg;
+       u32 sgl_nents = cmd->t_data_nents;
+       enum dma_data_direction data_direction = cmd->data_direction;
        struct se_device *dev = cmd->se_dev;
        struct iblock_req *ibr;
        struct bio *bio;
@@ -642,6 +740,18 @@ static void iblock_bio_done(struct bio *bio, int err)
        iblock_complete_cmd(cmd);
 }
 
+static struct spc_ops iblock_spc_ops = {
+       .execute_rw             = iblock_execute_rw,
+       .execute_sync_cache     = iblock_execute_sync_cache,
+       .execute_write_same     = iblock_execute_write_same,
+       .execute_unmap          = iblock_execute_unmap,
+};
+
+static int iblock_parse_cdb(struct se_cmd *cmd)
+{
+       return sbc_parse_cdb(cmd, &iblock_spc_ops);
+}
+
 static struct se_subsystem_api iblock_template = {
        .name                   = "iblock",
        .owner                  = THIS_MODULE,
@@ -653,9 +763,7 @@ static struct se_subsystem_api iblock_template = {
        .allocate_virtdevice    = iblock_allocate_virtdevice,
        .create_virtdevice      = iblock_create_virtdevice,
        .free_device            = iblock_free_device,
-       .execute_cmd            = iblock_execute_cmd,
-       .do_discard             = iblock_do_discard,
-       .do_sync_cache          = iblock_emulate_sync_cache,
+       .parse_cdb              = iblock_parse_cdb,
        .check_configfs_dev_params = iblock_check_configfs_dev_params,
        .set_configfs_dev_params = iblock_set_configfs_dev_params,
        .show_configfs_dev_params = iblock_show_configfs_dev_params,
index 66cf7b9e205edbf799ff77d963bd841f8d87972c..533627ae79ec8b1d49d4d2288e08e645d562a725 100644 (file)
@@ -18,6 +18,7 @@ struct iblock_dev {
        u32     ibd_flags;
        struct bio_set  *ibd_bio_set;
        struct block_device *ibd_bd;
+       bool ibd_readonly;
 } ____cacheline_aligned;
 
 #endif /* TARGET_CORE_IBLOCK_H */
index 165e82429687a49978c368598e20851ec91df0ae..0fd428225d115af6b4b3afbcc3d0beaaade73ebc 100644 (file)
@@ -4,25 +4,16 @@
 /* target_core_alua.c */
 extern struct t10_alua_lu_gp *default_lu_gp;
 
-/* target_core_cdb.c */
-int    target_emulate_inquiry(struct se_cmd *cmd);
-int    target_emulate_readcapacity(struct se_cmd *cmd);
-int    target_emulate_readcapacity_16(struct se_cmd *cmd);
-int    target_emulate_modesense(struct se_cmd *cmd);
-int    target_emulate_request_sense(struct se_cmd *cmd);
-int    target_emulate_unmap(struct se_cmd *cmd);
-int    target_emulate_write_same(struct se_cmd *cmd);
-int    target_emulate_synchronize_cache(struct se_cmd *cmd);
-int    target_emulate_noop(struct se_cmd *cmd);
-
 /* target_core_device.c */
 struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
 int    core_free_device_list_for_node(struct se_node_acl *,
                struct se_portal_group *);
 void   core_dec_lacl_count(struct se_node_acl *, struct se_cmd *);
 void   core_update_device_list_access(u32, u32, struct se_node_acl *);
-int    core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *,
-               u32, u32, struct se_node_acl *, struct se_portal_group *, int);
+int    core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *,
+               u32, u32, struct se_node_acl *, struct se_portal_group *);
+int    core_disable_device_list_for_node(struct se_lun *, struct se_lun_acl *,
+               u32, u32, struct se_node_acl *, struct se_portal_group *);
 void   core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *);
 int    core_dev_export(struct se_device *, struct se_portal_group *,
                struct se_lun *);
@@ -56,8 +47,7 @@ int   se_dev_set_max_sectors(struct se_device *, u32);
 int    se_dev_set_fabric_max_sectors(struct se_device *, u32);
 int    se_dev_set_optimal_sectors(struct se_device *, u32);
 int    se_dev_set_block_size(struct se_device *, u32);
-struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *,
-               struct se_device *, u32);
+struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u32);
 int    core_dev_del_lun(struct se_portal_group *, u32);
 struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32);
 struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *,
@@ -104,7 +94,6 @@ void release_se_kmem_caches(void);
 u32    scsi_get_new_index(scsi_index_t);
 void   transport_subsystem_check_init(void);
 void   transport_cmd_finish_abort(struct se_cmd *, int);
-void   __target_remove_from_execute_list(struct se_cmd *);
 unsigned char *transport_dump_cmd_direction(struct se_cmd *);
 void   transport_dump_dev_state(struct se_device *, char *, int *);
 void   transport_dump_dev_info(struct se_device *, struct se_lun *,
@@ -116,6 +105,7 @@ int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);
 bool   target_stop_cmd(struct se_cmd *cmd, unsigned long *flags);
 int    transport_clear_lun_from_sessions(struct se_lun *);
 void   transport_send_task_abort(struct se_cmd *);
+int    target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
 
 /* target_core_stat.c */
 void   target_stat_setup_dev_default_groups(struct se_subsystem_dev *);
index 85564998500a5bc1330fefbd0860a5425fda5939..1e946502c378886aa90bafc16239d2c34730b9fb 100644 (file)
@@ -507,7 +507,7 @@ static int core_scsi3_pr_seq_non_holder(
         * Check if write exclusive initiator ports *NOT* holding the
         * WRITE_EXCLUSIVE_* reservation.
         */
-       if ((we) && !(registered_nexus)) {
+       if (we && !registered_nexus) {
                if (cmd->data_direction == DMA_TO_DEVICE) {
                        /*
                         * Conflict for write exclusive
@@ -2031,7 +2031,7 @@ static int __core_scsi3_write_aptpl_to_file(
        if (IS_ERR(file) || !file || !file->f_dentry) {
                pr_err("filp_open(%s) for APTPL metadata"
                        " failed\n", path);
-               return (PTR_ERR(file) < 0 ? PTR_ERR(file) : -ENOENT);
+               return IS_ERR(file) ? PTR_ERR(file) : -ENOENT;
        }
 
        iov[0].iov_base = &buf[0];
@@ -2486,7 +2486,7 @@ static int core_scsi3_pro_reserve(
         */
        spin_lock(&dev->dev_reservation_lock);
        pr_res_holder = dev->dev_pr_res_holder;
-       if ((pr_res_holder)) {
+       if (pr_res_holder) {
                /*
                 * From spc4r17 Section 5.7.9: Reserving:
                 *
@@ -3818,7 +3818,7 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd)
                        " SPC-2 reservation is held, returning"
                        " RESERVATION_CONFLICT\n");
                cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
-               ret = EINVAL;
+               ret = -EINVAL;
                goto out;
        }
 
@@ -3828,7 +3828,8 @@ int target_scsi3_emulate_pr_out(struct se_cmd *cmd)
         */
        if (!cmd->se_sess) {
                cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        if (cmd->data_length < 24) {
@@ -4029,7 +4030,7 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd)
 
        spin_lock(&se_dev->dev_reservation_lock);
        pr_reg = se_dev->dev_pr_res_holder;
-       if ((pr_reg)) {
+       if (pr_reg) {
                /*
                 * Set the hardcoded Additional Length
                 */
index 4ce2cf642fced270ee727e83a81385467b9d9537..6e32ff6f2fa0ce4ead43073d87bedc77d3ffee2c 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/genhd.h>
 #include <linux/cdrom.h>
-#include <linux/file.h>
+#include <linux/ratelimit.h>
 #include <linux/module.h>
+#include <asm/unaligned.h>
+
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
 
+#include "target_core_alua.h"
 #include "target_core_pscsi.h"
 
 #define ISPRINT(a)  ((a >= ' ') && (a <= '~'))
 
 static struct se_subsystem_api pscsi_template;
 
+static int pscsi_execute_cmd(struct se_cmd *cmd);
 static void pscsi_req_done(struct request *, int);
 
 /*     pscsi_attach_hba():
@@ -1019,9 +1023,79 @@ fail:
        return -ENOMEM;
 }
 
-static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-               u32 sgl_nents, enum dma_data_direction data_direction)
+/*
+ * Clear a lun set in the cdb if the initiator talking to use spoke
+ * and old standards version, as we can't assume the underlying device
+ * won't choke up on it.
+ */
+static inline void pscsi_clear_cdb_lun(unsigned char *cdb)
+{
+       switch (cdb[0]) {
+       case READ_10: /* SBC - RDProtect */
+       case READ_12: /* SBC - RDProtect */
+       case READ_16: /* SBC - RDProtect */
+       case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
+       case VERIFY: /* SBC - VRProtect */
+       case VERIFY_16: /* SBC - VRProtect */
+       case WRITE_VERIFY: /* SBC - VRProtect */
+       case WRITE_VERIFY_12: /* SBC - VRProtect */
+       case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
+               break;
+       default:
+               cdb[1] &= 0x1f; /* clear logical unit number */
+               break;
+       }
+}
+
+static int pscsi_parse_cdb(struct se_cmd *cmd)
+{
+       unsigned char *cdb = cmd->t_task_cdb;
+       unsigned int dummy_size;
+       int ret;
+
+       if (cmd->se_cmd_flags & SCF_BIDI) {
+               cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+               return -EINVAL;
+       }
+
+       pscsi_clear_cdb_lun(cdb);
+
+       /*
+        * For REPORT LUNS we always need to emulate the response, for everything
+        * else the default for pSCSI is to pass the command to the underlying
+        * LLD / physical hardware.
+        */
+       switch (cdb[0]) {
+       case REPORT_LUNS:
+               ret = spc_parse_cdb(cmd, &dummy_size);
+               if (ret)
+                       return ret;
+               break;
+       case READ_6:
+       case READ_10:
+       case READ_12:
+       case READ_16:
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_12:
+       case WRITE_16:
+       case WRITE_VERIFY:
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               /* FALLTHROUGH*/
+       default:
+               cmd->execute_cmd = pscsi_execute_cmd;
+               break;
+       }
+
+       return 0;
+}
+
+static int pscsi_execute_cmd(struct se_cmd *cmd)
 {
+       struct scatterlist *sgl = cmd->t_data_sg;
+       u32 sgl_nents = cmd->t_data_nents;
+       enum dma_data_direction data_direction = cmd->data_direction;
        struct pscsi_dev_virt *pdv = cmd->se_dev->dev_ptr;
        struct pscsi_plugin_task *pt;
        struct request *req;
@@ -1042,7 +1116,7 @@ static int pscsi_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
        memcpy(pt->pscsi_cdb, cmd->t_task_cdb,
                scsi_command_size(cmd->t_task_cdb));
 
-       if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
+       if (!sgl) {
                req = blk_get_request(pdv->pdv_sd->request_queue,
                                (data_direction == DMA_TO_DEVICE),
                                GFP_KERNEL);
@@ -1188,7 +1262,7 @@ static struct se_subsystem_api pscsi_template = {
        .create_virtdevice      = pscsi_create_virtdevice,
        .free_device            = pscsi_free_device,
        .transport_complete     = pscsi_transport_complete,
-       .execute_cmd            = pscsi_execute_cmd,
+       .parse_cdb              = pscsi_parse_cdb,
        .check_configfs_dev_params = pscsi_check_configfs_dev_params,
        .set_configfs_dev_params = pscsi_set_configfs_dev_params,
        .show_configfs_dev_params = pscsi_show_configfs_dev_params,
index d0ceb873c0e577bc363971b10605228c804ae5d0..d00bbe33ff8b285f7777eaaf420d802e589169c2 100644 (file)
@@ -284,9 +284,11 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
        return NULL;
 }
 
-static int rd_execute_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
-               u32 sgl_nents, enum dma_data_direction data_direction)
+static int rd_execute_rw(struct se_cmd *cmd)
 {
+       struct scatterlist *sgl = cmd->t_data_sg;
+       u32 sgl_nents = cmd->t_data_nents;
+       enum dma_data_direction data_direction = cmd->data_direction;
        struct se_device *se_dev = cmd->se_dev;
        struct rd_dev *dev = se_dev->dev_ptr;
        struct rd_dev_sg_table *table;
@@ -460,6 +462,15 @@ static sector_t rd_get_blocks(struct se_device *dev)
        return blocks_long;
 }
 
+static struct spc_ops rd_spc_ops = {
+       .execute_rw             = rd_execute_rw,
+};
+
+static int rd_parse_cdb(struct se_cmd *cmd)
+{
+       return sbc_parse_cdb(cmd, &rd_spc_ops);
+}
+
 static struct se_subsystem_api rd_mcp_template = {
        .name                   = "rd_mcp",
        .transport_type         = TRANSPORT_PLUGIN_VHBA_VDEV,
@@ -468,7 +479,7 @@ static struct se_subsystem_api rd_mcp_template = {
        .allocate_virtdevice    = rd_allocate_virtdevice,
        .create_virtdevice      = rd_create_virtdevice,
        .free_device            = rd_free_device,
-       .execute_cmd            = rd_execute_cmd,
+       .parse_cdb              = rd_parse_cdb,
        .check_configfs_dev_params = rd_check_configfs_dev_params,
        .set_configfs_dev_params = rd_set_configfs_dev_params,
        .show_configfs_dev_params = rd_show_configfs_dev_params,
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
new file mode 100644 (file)
index 0000000..a9dd946
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * SCSI Block Commands (SBC) parsing and emulation.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+
+#include "target_core_internal.h"
+#include "target_core_ua.h"
+
+
+static int sbc_emulate_readcapacity(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       unsigned char *buf;
+       unsigned long long blocks_long = dev->transport->get_blocks(dev);
+       u32 blocks;
+
+       if (blocks_long >= 0x00000000ffffffff)
+               blocks = 0xffffffff;
+       else
+               blocks = (u32)blocks_long;
+
+       buf = transport_kmap_data_sg(cmd);
+
+       buf[0] = (blocks >> 24) & 0xff;
+       buf[1] = (blocks >> 16) & 0xff;
+       buf[2] = (blocks >> 8) & 0xff;
+       buf[3] = blocks & 0xff;
+       buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
+       buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
+       buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
+       buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
+
+       transport_kunmap_data_sg(cmd);
+
+       target_complete_cmd(cmd, GOOD);
+       return 0;
+}
+
+static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       unsigned char *buf;
+       unsigned long long blocks = dev->transport->get_blocks(dev);
+
+       buf = transport_kmap_data_sg(cmd);
+
+       buf[0] = (blocks >> 56) & 0xff;
+       buf[1] = (blocks >> 48) & 0xff;
+       buf[2] = (blocks >> 40) & 0xff;
+       buf[3] = (blocks >> 32) & 0xff;
+       buf[4] = (blocks >> 24) & 0xff;
+       buf[5] = (blocks >> 16) & 0xff;
+       buf[6] = (blocks >> 8) & 0xff;
+       buf[7] = blocks & 0xff;
+       buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
+       buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
+       buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
+       buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
+       /*
+        * Set Thin Provisioning Enable bit following sbc3r22 in section
+        * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
+        */
+       if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
+               buf[14] = 0x80;
+
+       transport_kunmap_data_sg(cmd);
+
+       target_complete_cmd(cmd, GOOD);
+       return 0;
+}
+
+int spc_get_write_same_sectors(struct se_cmd *cmd)
+{
+       u32 num_blocks;
+
+       if (cmd->t_task_cdb[0] == WRITE_SAME)
+               num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
+       else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
+               num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
+       else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
+               num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
+
+       /*
+        * Use the explicit range when non zero is supplied, otherwise calculate
+        * the remaining range based on ->get_blocks() - starting LBA.
+        */
+       if (num_blocks)
+               return num_blocks;
+
+       return cmd->se_dev->transport->get_blocks(cmd->se_dev) -
+               cmd->t_task_lba + 1;
+}
+EXPORT_SYMBOL(spc_get_write_same_sectors);
+
+static int sbc_emulate_verify(struct se_cmd *cmd)
+{
+       target_complete_cmd(cmd, GOOD);
+       return 0;
+}
+
+static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
+{
+       return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors;
+}
+
+static int sbc_check_valid_sectors(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       unsigned long long end_lba;
+       u32 sectors;
+
+       sectors = cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size;
+       end_lba = dev->transport->get_blocks(dev) + 1;
+
+       if (cmd->t_task_lba + sectors > end_lba) {
+               pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n",
+                       cmd->t_task_lba, sectors, end_lba);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static inline u32 transport_get_sectors_6(unsigned char *cdb)
+{
+       /*
+        * Use 8-bit sector value.  SBC-3 says:
+        *
+        *   A TRANSFER LENGTH field set to zero specifies that 256
+        *   logical blocks shall be written.  Any other value
+        *   specifies the number of logical blocks that shall be
+        *   written.
+        */
+       return cdb[4] ? : 256;
+}
+
+static inline u32 transport_get_sectors_10(unsigned char *cdb)
+{
+       return (u32)(cdb[7] << 8) + cdb[8];
+}
+
+static inline u32 transport_get_sectors_12(unsigned char *cdb)
+{
+       return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
+}
+
+static inline u32 transport_get_sectors_16(unsigned char *cdb)
+{
+       return (u32)(cdb[10] << 24) + (cdb[11] << 16) +
+                   (cdb[12] << 8) + cdb[13];
+}
+
+/*
+ * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants
+ */
+static inline u32 transport_get_sectors_32(unsigned char *cdb)
+{
+       return (u32)(cdb[28] << 24) + (cdb[29] << 16) +
+                   (cdb[30] << 8) + cdb[31];
+
+}
+
+static inline u32 transport_lba_21(unsigned char *cdb)
+{
+       return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
+}
+
+static inline u32 transport_lba_32(unsigned char *cdb)
+{
+       return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+}
+
+static inline unsigned long long transport_lba_64(unsigned char *cdb)
+{
+       unsigned int __v1, __v2;
+
+       __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+       __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+
+       return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+/*
+ * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs
+ */
+static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
+{
+       unsigned int __v1, __v2;
+
+       __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15];
+       __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19];
+
+       return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+static int sbc_write_same_supported(struct se_device *dev,
+               unsigned char *flags)
+{
+       if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
+               pr_err("WRITE_SAME PBDATA and LBDATA"
+                       " bits not supported for Block Discard"
+                       " Emulation\n");
+               return -ENOSYS;
+       }
+
+       /*
+        * Currently for the emulated case we only accept
+        * tpws with the UNMAP=1 bit set.
+        */
+       if (!(flags[0] & 0x08)) {
+               pr_err("WRITE_SAME w/o UNMAP bit not"
+                       " supported for Block Discard Emulation\n");
+               return -ENOSYS;
+       }
+
+       return 0;
+}
+
+static void xdreadwrite_callback(struct se_cmd *cmd)
+{
+       unsigned char *buf, *addr;
+       struct scatterlist *sg;
+       unsigned int offset;
+       int i;
+       int count;
+       /*
+        * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
+        *
+        * 1) read the specified logical block(s);
+        * 2) transfer logical blocks from the data-out buffer;
+        * 3) XOR the logical blocks transferred from the data-out buffer with
+        *    the logical blocks read, storing the resulting XOR data in a buffer;
+        * 4) if the DISABLE WRITE bit is set to zero, then write the logical
+        *    blocks transferred from the data-out buffer; and
+        * 5) transfer the resulting XOR data to the data-in buffer.
+        */
+       buf = kmalloc(cmd->data_length, GFP_KERNEL);
+       if (!buf) {
+               pr_err("Unable to allocate xor_callback buf\n");
+               return;
+       }
+       /*
+        * Copy the scatterlist WRITE buffer located at cmd->t_data_sg
+        * into the locally allocated *buf
+        */
+       sg_copy_to_buffer(cmd->t_data_sg,
+                         cmd->t_data_nents,
+                         buf,
+                         cmd->data_length);
+
+       /*
+        * Now perform the XOR against the BIDI read memory located at
+        * cmd->t_mem_bidi_list
+        */
+
+       offset = 0;
+       for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) {
+               addr = kmap_atomic(sg_page(sg));
+               if (!addr)
+                       goto out;
+
+               for (i = 0; i < sg->length; i++)
+                       *(addr + sg->offset + i) ^= *(buf + offset + i);
+
+               offset += sg->length;
+               kunmap_atomic(addr);
+       }
+
+out:
+       kfree(buf);
+}
+
+int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)
+{
+       struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
+       struct se_device *dev = cmd->se_dev;
+       unsigned char *cdb = cmd->t_task_cdb;
+       unsigned int size;
+       u32 sectors = 0;
+       int ret;
+
+       switch (cdb[0]) {
+       case READ_6:
+               sectors = transport_get_sectors_6(cdb);
+               cmd->t_task_lba = transport_lba_21(cdb);
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case READ_10:
+               sectors = transport_get_sectors_10(cdb);
+               cmd->t_task_lba = transport_lba_32(cdb);
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case READ_12:
+               sectors = transport_get_sectors_12(cdb);
+               cmd->t_task_lba = transport_lba_32(cdb);
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case READ_16:
+               sectors = transport_get_sectors_16(cdb);
+               cmd->t_task_lba = transport_lba_64(cdb);
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case WRITE_6:
+               sectors = transport_get_sectors_6(cdb);
+               cmd->t_task_lba = transport_lba_21(cdb);
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case WRITE_10:
+       case WRITE_VERIFY:
+               sectors = transport_get_sectors_10(cdb);
+               cmd->t_task_lba = transport_lba_32(cdb);
+               if (cdb[1] & 0x8)
+                       cmd->se_cmd_flags |= SCF_FUA;
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case WRITE_12:
+               sectors = transport_get_sectors_12(cdb);
+               cmd->t_task_lba = transport_lba_32(cdb);
+               if (cdb[1] & 0x8)
+                       cmd->se_cmd_flags |= SCF_FUA;
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case WRITE_16:
+               sectors = transport_get_sectors_16(cdb);
+               cmd->t_task_lba = transport_lba_64(cdb);
+               if (cdb[1] & 0x8)
+                       cmd->se_cmd_flags |= SCF_FUA;
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+               cmd->execute_cmd = ops->execute_rw;
+               break;
+       case XDWRITEREAD_10:
+               if ((cmd->data_direction != DMA_TO_DEVICE) ||
+                   !(cmd->se_cmd_flags & SCF_BIDI))
+                       goto out_invalid_cdb_field;
+               sectors = transport_get_sectors_10(cdb);
+
+               cmd->t_task_lba = transport_lba_32(cdb);
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+
+               /*
+                * Setup BIDI XOR callback to be run after I/O completion.
+                */
+               cmd->execute_cmd = ops->execute_rw;
+               cmd->transport_complete_callback = &xdreadwrite_callback;
+               if (cdb[1] & 0x8)
+                       cmd->se_cmd_flags |= SCF_FUA;
+               break;
+       case VARIABLE_LENGTH_CMD:
+       {
+               u16 service_action = get_unaligned_be16(&cdb[8]);
+               switch (service_action) {
+               case XDWRITEREAD_32:
+                       sectors = transport_get_sectors_32(cdb);
+
+                       /*
+                        * Use WRITE_32 and READ_32 opcodes for the emulated
+                        * XDWRITE_READ_32 logic.
+                        */
+                       cmd->t_task_lba = transport_lba_64_ext(cdb);
+                       cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
+
+                       /*
+                        * Setup BIDI XOR callback to be run during after I/O
+                        * completion.
+                        */
+                       cmd->execute_cmd = ops->execute_rw;
+                       cmd->transport_complete_callback = &xdreadwrite_callback;
+                       if (cdb[1] & 0x8)
+                               cmd->se_cmd_flags |= SCF_FUA;
+                       break;
+               case WRITE_SAME_32:
+                       if (!ops->execute_write_same)
+                               goto out_unsupported_cdb;
+
+                       sectors = transport_get_sectors_32(cdb);
+                       if (!sectors) {
+                               pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
+                                      " supported\n");
+                               goto out_invalid_cdb_field;
+                       }
+
+                       size = sbc_get_size(cmd, 1);
+                       cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
+
+                       if (sbc_write_same_supported(dev, &cdb[10]) < 0)
+                               goto out_unsupported_cdb;
+                       cmd->execute_cmd = ops->execute_write_same;
+                       break;
+               default:
+                       pr_err("VARIABLE_LENGTH_CMD service action"
+                               " 0x%04x not supported\n", service_action);
+                       goto out_unsupported_cdb;
+               }
+               break;
+       }
+       case READ_CAPACITY:
+               size = READ_CAP_LEN;
+               cmd->execute_cmd = sbc_emulate_readcapacity;
+               break;
+       case SERVICE_ACTION_IN:
+               switch (cmd->t_task_cdb[1] & 0x1f) {
+               case SAI_READ_CAPACITY_16:
+                       cmd->execute_cmd = sbc_emulate_readcapacity_16;
+                       break;
+               default:
+                       pr_err("Unsupported SA: 0x%02x\n",
+                               cmd->t_task_cdb[1] & 0x1f);
+                       goto out_invalid_cdb_field;
+               }
+               size = (cdb[10] << 24) | (cdb[11] << 16) |
+                      (cdb[12] << 8) | cdb[13];
+               break;
+       case SYNCHRONIZE_CACHE:
+       case SYNCHRONIZE_CACHE_16:
+               if (!ops->execute_sync_cache)
+                       goto out_unsupported_cdb;
+
+               /*
+                * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
+                */
+               if (cdb[0] == SYNCHRONIZE_CACHE) {
+                       sectors = transport_get_sectors_10(cdb);
+                       cmd->t_task_lba = transport_lba_32(cdb);
+               } else {
+                       sectors = transport_get_sectors_16(cdb);
+                       cmd->t_task_lba = transport_lba_64(cdb);
+               }
+
+               size = sbc_get_size(cmd, sectors);
+
+               /*
+                * Check to ensure that LBA + Range does not exceed past end of
+                * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
+                */
+               if (cmd->t_task_lba || sectors) {
+                       if (sbc_check_valid_sectors(cmd) < 0)
+                               goto out_invalid_cdb_field;
+               }
+               cmd->execute_cmd = ops->execute_sync_cache;
+               break;
+       case UNMAP:
+               if (!ops->execute_unmap)
+                       goto out_unsupported_cdb;
+
+               size = get_unaligned_be16(&cdb[7]);
+               cmd->execute_cmd = ops->execute_unmap;
+               break;
+       case WRITE_SAME_16:
+               if (!ops->execute_write_same)
+                       goto out_unsupported_cdb;
+
+               sectors = transport_get_sectors_16(cdb);
+               if (!sectors) {
+                       pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
+                       goto out_invalid_cdb_field;
+               }
+
+               size = sbc_get_size(cmd, 1);
+               cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
+
+               if (sbc_write_same_supported(dev, &cdb[1]) < 0)
+                       goto out_unsupported_cdb;
+               cmd->execute_cmd = ops->execute_write_same;
+               break;
+       case WRITE_SAME:
+               if (!ops->execute_write_same)
+                       goto out_unsupported_cdb;
+
+               sectors = transport_get_sectors_10(cdb);
+               if (!sectors) {
+                       pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
+                       goto out_invalid_cdb_field;
+               }
+
+               size = sbc_get_size(cmd, 1);
+               cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
+
+               /*
+                * Follow sbcr26 with WRITE_SAME (10) and check for the existence
+                * of byte 1 bit 3 UNMAP instead of original reserved field
+                */
+               if (sbc_write_same_supported(dev, &cdb[1]) < 0)
+                       goto out_unsupported_cdb;
+               cmd->execute_cmd = ops->execute_write_same;
+               break;
+       case VERIFY:
+               size = 0;
+               cmd->execute_cmd = sbc_emulate_verify;
+               break;
+       default:
+               ret = spc_parse_cdb(cmd, &size);
+               if (ret)
+                       return ret;
+       }
+
+       /* reject any command that we don't have a handler for */
+       if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->execute_cmd)
+               goto out_unsupported_cdb;
+
+       if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
+               unsigned long long end_lba;
+
+               if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) {
+                       printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
+                               " big sectors %u exceeds fabric_max_sectors:"
+                               " %u\n", cdb[0], sectors,
+                               su_dev->se_dev_attrib.fabric_max_sectors);
+                       goto out_invalid_cdb_field;
+               }
+               if (sectors > su_dev->se_dev_attrib.hw_max_sectors) {
+                       printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
+                               " big sectors %u exceeds backend hw_max_sectors:"
+                               " %u\n", cdb[0], sectors,
+                               su_dev->se_dev_attrib.hw_max_sectors);
+                       goto out_invalid_cdb_field;
+               }
+
+               end_lba = dev->transport->get_blocks(dev) + 1;
+               if (cmd->t_task_lba + sectors > end_lba) {
+                       pr_err("cmd exceeds last lba %llu "
+                               "(lba %llu, sectors %u)\n",
+                               end_lba, cmd->t_task_lba, sectors);
+                       goto out_invalid_cdb_field;
+               }
+
+               size = sbc_get_size(cmd, sectors);
+       }
+
+       ret = target_cmd_size_check(cmd, size);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+
+out_unsupported_cdb:
+       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+       cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+       return -EINVAL;
+out_invalid_cdb_field:
+       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+       cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+       return -EINVAL;
+}
+EXPORT_SYMBOL(sbc_parse_cdb);
similarity index 76%
rename from drivers/target/target_core_cdb.c
rename to drivers/target/target_core_spc.c
index 9888693a18fe0c7a024ef150483097a12e19fcc4..4c861de538c9ddb627356e8aa3ea992b164033cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * CDB emulation for non-READ/WRITE commands.
+ * SCSI Primary Commands (SPC) parsing and emulation.
  *
  * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
  * Copyright (c) 2005, 2006, 2007 SBE, Inc.
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <asm/unaligned.h>
+
 #include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
 #include <target/target_core_fabric.h>
 
 #include "target_core_internal.h"
+#include "target_core_alua.h"
+#include "target_core_pr.h"
 #include "target_core_ua.h"
 
-static void
-target_fill_alua_data(struct se_port *port, unsigned char *buf)
+
+static void spc_fill_alua_data(struct se_port *port, unsigned char *buf)
 {
        struct t10_alua_tg_pt_gp *tg_pt_gp;
        struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
@@ -65,8 +69,7 @@ target_fill_alua_data(struct se_port *port, unsigned char *buf)
        spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
 }
 
-static int
-target_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
+static int spc_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
 {
        struct se_lun *lun = cmd->se_lun;
        struct se_device *dev = cmd->se_dev;
@@ -93,7 +96,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
         * Enable SCCS and TPGS fields for Emulated ALUA
         */
        if (dev->se_sub_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED)
-               target_fill_alua_data(lun->lun_sep, buf);
+               spc_fill_alua_data(lun->lun_sep, buf);
 
        buf[7] = 0x2; /* CmdQue=1 */
 
@@ -106,8 +109,7 @@ target_emulate_inquiry_std(struct se_cmd *cmd, char *buf)
 }
 
 /* unit serial number */
-static int
-target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
+static int spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
 {
        struct se_device *dev = cmd->se_dev;
        u16 len = 0;
@@ -127,8 +129,8 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
        return 0;
 }
 
-static void
-target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf)
+static void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
+               unsigned char *buf)
 {
        unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0];
        int cnt;
@@ -162,8 +164,7 @@ target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf)
  * Device identification VPD, for a complete list of
  * DESIGNATOR TYPEs see spc4r17 Table 459.
  */
-static int
-target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
+static int spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_lun *lun = cmd->se_lun;
@@ -220,7 +221,7 @@ target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
         * VENDOR_SPECIFIC_IDENTIFIER and
         * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
         */
-       target_parse_naa_6h_vendor_specific(dev, &buf[off]);
+       spc_parse_naa_6h_vendor_specific(dev, &buf[off]);
 
        len = 20;
        off = (len + 4);
@@ -414,8 +415,7 @@ check_scsi_name:
 }
 
 /* Extended INQUIRY Data VPD Page */
-static int
-target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
+static int spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
 {
        buf[3] = 0x3c;
        /* Set HEADSUP, ORDSUP, SIMPSUP */
@@ -428,15 +428,14 @@ target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
 }
 
 /* Block Limits VPD page */
-static int
-target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
+static int spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
 {
        struct se_device *dev = cmd->se_dev;
        u32 max_sectors;
        int have_tp = 0;
 
        /*
-        * Following sbc3r22 section 6.5.3 Block Limits VPD page, when
+        * Following spc3r22 section 6.5.3 Block Limits VPD page, when
         * emulate_tpu=1 or emulate_tpws=1 we will be expect a
         * different page length for Thin Provisioning.
         */
@@ -500,8 +499,7 @@ target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
 }
 
 /* Block Device Characteristics VPD page */
-static int
-target_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf)
+static int spc_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf)
 {
        struct se_device *dev = cmd->se_dev;
 
@@ -513,13 +511,12 @@ target_emulate_evpd_b1(struct se_cmd *cmd, unsigned char *buf)
 }
 
 /* Thin Provisioning VPD */
-static int
-target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
+static int spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
 {
        struct se_device *dev = cmd->se_dev;
 
        /*
-        * From sbc3r22 section 6.5.4 Thin Provisioning VPD page:
+        * From spc3r22 section 6.5.4 Thin Provisioning VPD page:
         *
         * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to
         * zero, then the page length shall be set to 0004h.  If the DP bit
@@ -564,25 +561,23 @@ target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
        return 0;
 }
 
-static int
-target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);
+static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);
 
 static struct {
        uint8_t         page;
        int             (*emulate)(struct se_cmd *, unsigned char *);
 } evpd_handlers[] = {
-       { .page = 0x00, .emulate = target_emulate_evpd_00 },
-       { .page = 0x80, .emulate = target_emulate_evpd_80 },
-       { .page = 0x83, .emulate = target_emulate_evpd_83 },
-       { .page = 0x86, .emulate = target_emulate_evpd_86 },
-       { .page = 0xb0, .emulate = target_emulate_evpd_b0 },
-       { .page = 0xb1, .emulate = target_emulate_evpd_b1 },
-       { .page = 0xb2, .emulate = target_emulate_evpd_b2 },
+       { .page = 0x00, .emulate = spc_emulate_evpd_00 },
+       { .page = 0x80, .emulate = spc_emulate_evpd_80 },
+       { .page = 0x83, .emulate = spc_emulate_evpd_83 },
+       { .page = 0x86, .emulate = spc_emulate_evpd_86 },
+       { .page = 0xb0, .emulate = spc_emulate_evpd_b0 },
+       { .page = 0xb1, .emulate = spc_emulate_evpd_b1 },
+       { .page = 0xb2, .emulate = spc_emulate_evpd_b2 },
 };
 
 /* supported vital product data pages */
-static int
-target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
+static int spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
 {
        int p;
 
@@ -601,7 +596,7 @@ target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
        return 0;
 }
 
-int target_emulate_inquiry(struct se_cmd *cmd)
+static int spc_emulate_inquiry(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
@@ -643,7 +638,7 @@ int target_emulate_inquiry(struct se_cmd *cmd)
                        goto out;
                }
 
-               ret = target_emulate_inquiry_std(cmd, buf);
+               ret = spc_emulate_inquiry_std(cmd, buf);
                goto out;
        }
 
@@ -671,70 +666,7 @@ out:
        return ret;
 }
 
-int target_emulate_readcapacity(struct se_cmd *cmd)
-{
-       struct se_device *dev = cmd->se_dev;
-       unsigned char *buf;
-       unsigned long long blocks_long = dev->transport->get_blocks(dev);
-       u32 blocks;
-
-       if (blocks_long >= 0x00000000ffffffff)
-               blocks = 0xffffffff;
-       else
-               blocks = (u32)blocks_long;
-
-       buf = transport_kmap_data_sg(cmd);
-
-       buf[0] = (blocks >> 24) & 0xff;
-       buf[1] = (blocks >> 16) & 0xff;
-       buf[2] = (blocks >> 8) & 0xff;
-       buf[3] = blocks & 0xff;
-       buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
-       buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
-       buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
-       buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
-
-       transport_kunmap_data_sg(cmd);
-
-       target_complete_cmd(cmd, GOOD);
-       return 0;
-}
-
-int target_emulate_readcapacity_16(struct se_cmd *cmd)
-{
-       struct se_device *dev = cmd->se_dev;
-       unsigned char *buf;
-       unsigned long long blocks = dev->transport->get_blocks(dev);
-
-       buf = transport_kmap_data_sg(cmd);
-
-       buf[0] = (blocks >> 56) & 0xff;
-       buf[1] = (blocks >> 48) & 0xff;
-       buf[2] = (blocks >> 40) & 0xff;
-       buf[3] = (blocks >> 32) & 0xff;
-       buf[4] = (blocks >> 24) & 0xff;
-       buf[5] = (blocks >> 16) & 0xff;
-       buf[6] = (blocks >> 8) & 0xff;
-       buf[7] = blocks & 0xff;
-       buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
-       buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
-       buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
-       buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
-       /*
-        * Set Thin Provisioning Enable bit following sbc3r22 in section
-        * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
-        */
-       if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
-               buf[14] = 0x80;
-
-       transport_kunmap_data_sg(cmd);
-
-       target_complete_cmd(cmd, GOOD);
-       return 0;
-}
-
-static int
-target_modesense_rwrecovery(unsigned char *p)
+static int spc_modesense_rwrecovery(unsigned char *p)
 {
        p[0] = 0x01;
        p[1] = 0x0a;
@@ -742,8 +674,7 @@ target_modesense_rwrecovery(unsigned char *p)
        return 12;
 }
 
-static int
-target_modesense_control(struct se_device *dev, unsigned char *p)
+static int spc_modesense_control(struct se_device *dev, unsigned char *p)
 {
        p[0] = 0x0a;
        p[1] = 0x0a;
@@ -828,8 +759,7 @@ target_modesense_control(struct se_device *dev, unsigned char *p)
        return 12;
 }
 
-static int
-target_modesense_caching(struct se_device *dev, unsigned char *p)
+static int spc_modesense_caching(struct se_device *dev, unsigned char *p)
 {
        p[0] = 0x08;
        p[1] = 0x12;
@@ -840,8 +770,7 @@ target_modesense_caching(struct se_device *dev, unsigned char *p)
        return 20;
 }
 
-static void
-target_modesense_write_protect(unsigned char *buf, int type)
+static void spc_modesense_write_protect(unsigned char *buf, int type)
 {
        /*
         * I believe that the WP bit (bit 7) in the mode header is the same for
@@ -856,8 +785,7 @@ target_modesense_write_protect(unsigned char *buf, int type)
        }
 }
 
-static void
-target_modesense_dpofua(unsigned char *buf, int type)
+static void spc_modesense_dpofua(unsigned char *buf, int type)
 {
        switch (type) {
        case TYPE_DISK:
@@ -868,7 +796,7 @@ target_modesense_dpofua(unsigned char *buf, int type)
        }
 }
 
-int target_emulate_modesense(struct se_cmd *cmd)
+static int spc_emulate_modesense(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        char *cdb = cmd->t_task_cdb;
@@ -883,18 +811,18 @@ int target_emulate_modesense(struct se_cmd *cmd)
 
        switch (cdb[2] & 0x3f) {
        case 0x01:
-               length = target_modesense_rwrecovery(&buf[offset]);
+               length = spc_modesense_rwrecovery(&buf[offset]);
                break;
        case 0x08:
-               length = target_modesense_caching(dev, &buf[offset]);
+               length = spc_modesense_caching(dev, &buf[offset]);
                break;
        case 0x0a:
-               length = target_modesense_control(dev, &buf[offset]);
+               length = spc_modesense_control(dev, &buf[offset]);
                break;
        case 0x3f:
-               length = target_modesense_rwrecovery(&buf[offset]);
-               length += target_modesense_caching(dev, &buf[offset+length]);
-               length += target_modesense_control(dev, &buf[offset+length]);
+               length = spc_modesense_rwrecovery(&buf[offset]);
+               length += spc_modesense_caching(dev, &buf[offset+length]);
+               length += spc_modesense_control(dev, &buf[offset+length]);
                break;
        default:
                pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n",
@@ -912,11 +840,11 @@ int target_emulate_modesense(struct se_cmd *cmd)
                if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
                    (cmd->se_deve &&
                    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
-                       target_modesense_write_protect(&buf[3], type);
+                       spc_modesense_write_protect(&buf[3], type);
 
                if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
                    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
-                       target_modesense_dpofua(&buf[3], type);
+                       spc_modesense_dpofua(&buf[3], type);
 
                if ((offset + 2) > cmd->data_length)
                        offset = cmd->data_length;
@@ -928,11 +856,11 @@ int target_emulate_modesense(struct se_cmd *cmd)
                if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
                    (cmd->se_deve &&
                    (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
-                       target_modesense_write_protect(&buf[2], type);
+                       spc_modesense_write_protect(&buf[2], type);
 
                if ((dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0) &&
                    (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0))
-                       target_modesense_dpofua(&buf[2], type);
+                       spc_modesense_dpofua(&buf[2], type);
 
                if ((offset + 1) > cmd->data_length)
                        offset = cmd->data_length;
@@ -946,7 +874,7 @@ int target_emulate_modesense(struct se_cmd *cmd)
        return 0;
 }
 
-int target_emulate_request_sense(struct se_cmd *cmd)
+static int spc_emulate_request_sense(struct se_cmd *cmd)
 {
        unsigned char *cdb = cmd->t_task_cdb;
        unsigned char *buf;
@@ -1005,126 +933,172 @@ end:
        return 0;
 }
 
-/*
- * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
- * Note this is not used for TCM/pSCSI passthrough
- */
-int target_emulate_unmap(struct se_cmd *cmd)
+static int spc_emulate_testunitready(struct se_cmd *cmd)
 {
-       struct se_device *dev = cmd->se_dev;
-       unsigned char *buf, *ptr = NULL;
-       unsigned char *cdb = &cmd->t_task_cdb[0];
-       sector_t lba;
-       unsigned int size = cmd->data_length, range;
-       int ret = 0, offset;
-       unsigned short dl, bd_dl;
-
-       if (!dev->transport->do_discard) {
-               pr_err("UNMAP emulation not supported for: %s\n",
-                               dev->transport->name);
-               cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-               return -ENOSYS;
-       }
-
-       /* First UNMAP block descriptor starts at 8 byte offset */
-       offset = 8;
-       size -= 8;
-       dl = get_unaligned_be16(&cdb[0]);
-       bd_dl = get_unaligned_be16(&cdb[2]);
-
-       buf = transport_kmap_data_sg(cmd);
-
-       ptr = &buf[offset];
-       pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
-               " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
-
-       while (size) {
-               lba = get_unaligned_be64(&ptr[0]);
-               range = get_unaligned_be32(&ptr[8]);
-               pr_debug("UNMAP: Using lba: %llu and range: %u\n",
-                                (unsigned long long)lba, range);
-
-               ret = dev->transport->do_discard(dev, lba, range);
-               if (ret < 0) {
-                       pr_err("blkdev_issue_discard() failed: %d\n",
-                                       ret);
-                       goto err;
-               }
-
-               ptr += 16;
-               size -= 16;
-       }
-
-err:
-       transport_kunmap_data_sg(cmd);
-       if (!ret)
-               target_complete_cmd(cmd, GOOD);
-       return ret;
+       target_complete_cmd(cmd, GOOD);
+       return 0;
 }
 
-/*
- * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
- * Note this is not used for TCM/pSCSI passthrough
- */
-int target_emulate_write_same(struct se_cmd *cmd)
+int spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
 {
        struct se_device *dev = cmd->se_dev;
-       sector_t range;
-       sector_t lba = cmd->t_task_lba;
-       u32 num_blocks;
-       int ret;
-
-       if (!dev->transport->do_discard) {
-               pr_err("WRITE_SAME emulation not supported"
-                               " for: %s\n", dev->transport->name);
-               cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-               return -ENOSYS;
-       }
-
-       if (cmd->t_task_cdb[0] == WRITE_SAME)
-               num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
-       else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
-               num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
-       else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
-               num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
-
-       /*
-        * Use the explicit range when non zero is supplied, otherwise calculate
-        * the remaining range based on ->get_blocks() - starting LBA.
-        */
-       if (num_blocks != 0)
-               range = num_blocks;
-       else
-               range = (dev->transport->get_blocks(dev) - lba);
-
-       pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n",
-                (unsigned long long)lba, (unsigned long long)range);
+       struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+       unsigned char *cdb = cmd->t_task_cdb;
 
-       ret = dev->transport->do_discard(dev, lba, range);
-       if (ret < 0) {
-               pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n");
-               return ret;
-       }
+       switch (cdb[0]) {
+       case MODE_SELECT:
+               *size = cdb[4];
+               break;
+       case MODE_SELECT_10:
+               *size = (cdb[7] << 8) + cdb[8];
+               break;
+       case MODE_SENSE:
+               *size = cdb[4];
+               cmd->execute_cmd = spc_emulate_modesense;
+               break;
+       case MODE_SENSE_10:
+               *size = (cdb[7] << 8) + cdb[8];
+               cmd->execute_cmd = spc_emulate_modesense;
+               break;
+       case LOG_SELECT:
+       case LOG_SENSE:
+               *size = (cdb[7] << 8) + cdb[8];
+               break;
+       case PERSISTENT_RESERVE_IN:
+               if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
+                       cmd->execute_cmd = target_scsi3_emulate_pr_in;
+               *size = (cdb[7] << 8) + cdb[8];
+               break;
+       case PERSISTENT_RESERVE_OUT:
+               if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
+                       cmd->execute_cmd = target_scsi3_emulate_pr_out;
+               *size = (cdb[7] << 8) + cdb[8];
+               break;
+       case RELEASE:
+       case RELEASE_10:
+               if (cdb[0] == RELEASE_10)
+                       *size = (cdb[7] << 8) | cdb[8];
+               else
+                       *size = cmd->data_length;
+
+               if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
+                       cmd->execute_cmd = target_scsi2_reservation_release;
+               break;
+       case RESERVE:
+       case RESERVE_10:
+               /*
+                * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
+                * Assume the passthrough or $FABRIC_MOD will tell us about it.
+                */
+               if (cdb[0] == RESERVE_10)
+                       *size = (cdb[7] << 8) | cdb[8];
+               else
+                       *size = cmd->data_length;
 
-       target_complete_cmd(cmd, GOOD);
-       return 0;
-}
+               /*
+                * Setup the legacy emulated handler for SPC-2 and
+                * >= SPC-3 compatible reservation handling (CRH=1)
+                * Otherwise, we assume the underlying SCSI logic is
+                * is running in SPC_PASSTHROUGH, and wants reservations
+                * emulation disabled.
+                */
+               if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
+                       cmd->execute_cmd = target_scsi2_reservation_reserve;
+               break;
+       case REQUEST_SENSE:
+               *size = cdb[4];
+               cmd->execute_cmd = spc_emulate_request_sense;
+               break;
+       case INQUIRY:
+               *size = (cdb[3] << 8) + cdb[4];
 
-int target_emulate_synchronize_cache(struct se_cmd *cmd)
-{
-       if (!cmd->se_dev->transport->do_sync_cache) {
-               pr_err("SYNCHRONIZE_CACHE emulation not supported"
-                       " for: %s\n", cmd->se_dev->transport->name);
+               /*
+                * Do implict HEAD_OF_QUEUE processing for INQUIRY.
+                * See spc4r17 section 5.3
+                */
+               if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+                       cmd->sam_task_attr = MSG_HEAD_TAG;
+               cmd->execute_cmd = spc_emulate_inquiry;
+               break;
+       case SECURITY_PROTOCOL_IN:
+       case SECURITY_PROTOCOL_OUT:
+               *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+               break;
+       case EXTENDED_COPY:
+       case READ_ATTRIBUTE:
+       case RECEIVE_COPY_RESULTS:
+       case WRITE_ATTRIBUTE:
+               *size = (cdb[10] << 24) | (cdb[11] << 16) |
+                      (cdb[12] << 8) | cdb[13];
+               break;
+       case RECEIVE_DIAGNOSTIC:
+       case SEND_DIAGNOSTIC:
+               *size = (cdb[3] << 8) | cdb[4];
+               break;
+       case WRITE_BUFFER:
+               *size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+               break;
+       case REPORT_LUNS:
+               cmd->execute_cmd = target_report_luns;
+               *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+               /*
+                * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
+                * See spc4r17 section 5.3
+                */
+               if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+                       cmd->sam_task_attr = MSG_HEAD_TAG;
+               break;
+       case TEST_UNIT_READY:
+               cmd->execute_cmd = spc_emulate_testunitready;
+               *size = 0;
+               break;
+       case MAINTENANCE_IN:
+               if (dev->transport->get_device_type(dev) != TYPE_ROM) {
+                       /*
+                        * MAINTENANCE_IN from SCC-2
+                        * Check for emulated MI_REPORT_TARGET_PGS
+                        */
+                       if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS &&
+                           su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
+                               cmd->execute_cmd =
+                                       target_emulate_report_target_port_groups;
+                       }
+                       *size = get_unaligned_be32(&cdb[6]);
+               } else {
+                       /*
+                        * GPCMD_SEND_KEY from multi media commands
+                        */
+                       *size = get_unaligned_be16(&cdb[8]);
+               }
+               break;
+       case MAINTENANCE_OUT:
+               if (dev->transport->get_device_type(dev) != TYPE_ROM) {
+                       /*
+                        * MAINTENANCE_OUT from SCC-2
+                        * Check for emulated MO_SET_TARGET_PGS.
+                        */
+                       if (cdb[1] == MO_SET_TARGET_PGS &&
+                           su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
+                               cmd->execute_cmd =
+                                       target_emulate_set_target_port_groups;
+                       }
+                       *size = get_unaligned_be32(&cdb[6]);
+               } else {
+                       /*
+                        * GPCMD_SEND_KEY from multi media commands
+                        */
+                       *size = get_unaligned_be16(&cdb[8]);
+               }
+               break;
+       default:
+               pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
+                       " 0x%02x, sending CHECK_CONDITION.\n",
+                       cmd->se_tfo->get_fabric_name(), cdb[0]);
+               cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
                cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-               return -ENOSYS;
+               return -EINVAL;
        }
 
-       cmd->se_dev->transport->do_sync_cache(cmd);
-       return 0;
-}
-
-int target_emulate_noop(struct se_cmd *cmd)
-{
-       target_complete_cmd(cmd, GOOD);
        return 0;
 }
+EXPORT_SYMBOL(spc_parse_cdb);
index 84caf1bed9a3392ede0686851f5d90bae80bd83d..1c59a3c23b2c1b37ee8a3c54d62b8c66ea6f9e87 100644 (file)
@@ -295,9 +295,6 @@ static void core_tmr_drain_state_list(
 
                list_move_tail(&cmd->state_list, &drain_task_list);
                cmd->state_active = false;
-
-               if (!list_empty(&cmd->execute_list))
-                       __target_remove_from_execute_list(cmd);
        }
        spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 
@@ -354,57 +351,6 @@ static void core_tmr_drain_state_list(
        }
 }
 
-static void core_tmr_drain_cmd_list(
-       struct se_device *dev,
-       struct se_cmd *prout_cmd,
-       struct se_node_acl *tmr_nacl,
-       int tas,
-       struct list_head *preempt_and_abort_list)
-{
-       LIST_HEAD(drain_cmd_list);
-       struct se_queue_obj *qobj = &dev->dev_queue_obj;
-       struct se_cmd *cmd, *tcmd;
-       unsigned long flags;
-
-       /*
-        * Release all commands remaining in the per-device command queue.
-        *
-        * This follows the same logic as above for the state list.
-        */
-       spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
-       list_for_each_entry_safe(cmd, tcmd, &qobj->qobj_list, se_queue_node) {
-               /*
-                * For PREEMPT_AND_ABORT usage, only process commands
-                * with a matching reservation key.
-                */
-               if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
-                       continue;
-               /*
-                * Not aborting PROUT PREEMPT_AND_ABORT CDB..
-                */
-               if (prout_cmd == cmd)
-                       continue;
-
-               cmd->transport_state &= ~CMD_T_QUEUED;
-               atomic_dec(&qobj->queue_cnt);
-               list_move_tail(&cmd->se_queue_node, &drain_cmd_list);
-       }
-       spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-
-       while (!list_empty(&drain_cmd_list)) {
-               cmd = list_entry(drain_cmd_list.next, struct se_cmd, se_queue_node);
-               list_del_init(&cmd->se_queue_node);
-
-               pr_debug("LUN_RESET: %s from Device Queue: cmd: %p t_state:"
-                       " %d t_fe_count: %d\n", (preempt_and_abort_list) ?
-                       "Preempt" : "", cmd, cmd->t_state,
-                       atomic_read(&cmd->t_fe_count));
-
-               core_tmr_handle_tas_abort(tmr_nacl, cmd, tas,
-                               atomic_read(&cmd->t_fe_count));
-       }
-}
-
 int core_tmr_lun_reset(
         struct se_device *dev,
         struct se_tmr_req *tmr,
@@ -447,8 +393,7 @@ int core_tmr_lun_reset(
        core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
        core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas,
                                preempt_and_abort_list);
-       core_tmr_drain_cmd_list(dev, prout_cmd, tmr_nacl, tas,
-                               preempt_and_abort_list);
+
        /*
         * Clear any legacy SPC-2 reservation when called during
         * LOGICAL UNIT RESET
index 8bd58e284185bab23b8df5d4a554eeae945c8b04..b8628a5014b9ecb45151e52496845a33be06bfc2 100644 (file)
@@ -77,8 +77,8 @@ static void core_clear_initiator_node_from_tpg(
 
                lun = deve->se_lun;
                spin_unlock_irq(&nacl->device_list_lock);
-               core_update_device_list_for_node(lun, NULL, deve->mapped_lun,
-                       TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+               core_disable_device_list_for_node(lun, NULL, deve->mapped_lun,
+                       TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg);
 
                spin_lock_irq(&nacl->device_list_lock);
        }
@@ -172,8 +172,8 @@ void core_tpg_add_node_to_devs(
                        (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ?
                        "READ-WRITE" : "READ-ONLY");
 
-               core_update_device_list_for_node(lun, NULL, lun->unpacked_lun,
-                               lun_access, acl, tpg, 1);
+               core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun,
+                               lun_access, acl, tpg);
                spin_lock(&tpg->tpg_lun_lock);
        }
        spin_unlock(&tpg->tpg_lun_lock);
@@ -306,10 +306,8 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
         * TPG LUNs if the fabric is not explictly asking for
         * tpg_check_demo_mode_login_only() == 1.
         */
-       if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only != NULL) &&
-           (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) == 1))
-               do { ; } while (0);
-       else
+       if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only == NULL) ||
+           (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) != 1))
                core_tpg_add_node_to_devs(acl, tpg);
 
        spin_lock_irq(&tpg->acl_node_lock);
index 634d0f31a28cc59f621ea6122a13777c320339d5..0eaae23d12b576547fa51f25ed8f05579f6ec646 100644 (file)
@@ -66,15 +66,12 @@ struct kmem_cache *t10_alua_lu_gp_mem_cache;
 struct kmem_cache *t10_alua_tg_pt_gp_cache;
 struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
 
-static int transport_generic_write_pending(struct se_cmd *);
-static int transport_processing_thread(void *param);
-static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *);
 static void transport_complete_task_attr(struct se_cmd *cmd);
 static void transport_handle_queue_full(struct se_cmd *cmd,
                struct se_device *dev);
 static int transport_generic_get_mem(struct se_cmd *cmd);
+static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool);
 static void transport_put_cmd(struct se_cmd *cmd);
-static void transport_remove_cmd_from_queue(struct se_cmd *cmd);
 static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq);
 static void target_complete_ok_work(struct work_struct *work);
 
@@ -195,14 +192,6 @@ u32 scsi_get_new_index(scsi_index_t type)
        return new_index;
 }
 
-static void transport_init_queue_obj(struct se_queue_obj *qobj)
-{
-       atomic_set(&qobj->queue_cnt, 0);
-       INIT_LIST_HEAD(&qobj->qobj_list);
-       init_waitqueue_head(&qobj->thread_wq);
-       spin_lock_init(&qobj->cmd_queue_lock);
-}
-
 void transport_subsystem_check_init(void)
 {
        int ret;
@@ -243,7 +232,6 @@ struct se_session *transport_init_session(void)
        INIT_LIST_HEAD(&se_sess->sess_list);
        INIT_LIST_HEAD(&se_sess->sess_acl_list);
        INIT_LIST_HEAD(&se_sess->sess_cmd_list);
-       INIT_LIST_HEAD(&se_sess->sess_wait_list);
        spin_lock_init(&se_sess->sess_cmd_lock);
        kref_init(&se_sess->sess_kref);
 
@@ -468,18 +456,7 @@ static void target_remove_from_state_list(struct se_cmd *cmd)
        spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 }
 
-/*     transport_cmd_check_stop():
- *
- *     'transport_off = 1' determines if CMD_T_ACTIVE should be cleared.
- *     'transport_off = 2' determines if task_dev_state should be removed.
- *
- *     A non-zero u8 t_state sets cmd->t_state.
- *     Returns 1 when command is stopped, else 0.
- */
-static int transport_cmd_check_stop(
-       struct se_cmd *cmd,
-       int transport_off,
-       u8 t_state)
+static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists)
 {
        unsigned long flags;
 
@@ -493,13 +470,23 @@ static int transport_cmd_check_stop(
                        __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd));
 
                cmd->transport_state &= ~CMD_T_ACTIVE;
-               if (transport_off == 2)
+               if (remove_from_lists)
                        target_remove_from_state_list(cmd);
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
                complete(&cmd->transport_lun_stop_comp);
                return 1;
        }
+
+       if (remove_from_lists) {
+               target_remove_from_state_list(cmd);
+
+               /*
+                * Clear struct se_cmd->se_lun before the handoff to FE.
+                */
+               cmd->se_lun = NULL;
+       }
+
        /*
         * Determine if frontend context caller is requesting the stopping of
         * this command for frontend exceptions.
@@ -509,58 +496,36 @@ static int transport_cmd_check_stop(
                        __func__, __LINE__,
                        cmd->se_tfo->get_task_tag(cmd));
 
-               if (transport_off == 2)
-                       target_remove_from_state_list(cmd);
-
-               /*
-                * Clear struct se_cmd->se_lun before the transport_off == 2 handoff
-                * to FE.
-                */
-               if (transport_off == 2)
-                       cmd->se_lun = NULL;
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
                complete(&cmd->t_transport_stop_comp);
                return 1;
        }
-       if (transport_off) {
-               cmd->transport_state &= ~CMD_T_ACTIVE;
-               if (transport_off == 2) {
-                       target_remove_from_state_list(cmd);
-                       /*
-                        * Clear struct se_cmd->se_lun before the transport_off == 2
-                        * handoff to fabric module.
-                        */
-                       cmd->se_lun = NULL;
-                       /*
-                        * Some fabric modules like tcm_loop can release
-                        * their internally allocated I/O reference now and
-                        * struct se_cmd now.
-                        *
-                        * Fabric modules are expected to return '1' here if the
-                        * se_cmd being passed is released at this point,
-                        * or zero if not being released.
-                        */
-                       if (cmd->se_tfo->check_stop_free != NULL) {
-                               spin_unlock_irqrestore(
-                                       &cmd->t_state_lock, flags);
-
-                               return cmd->se_tfo->check_stop_free(cmd);
-                       }
+
+       cmd->transport_state &= ~CMD_T_ACTIVE;
+       if (remove_from_lists) {
+               /*
+                * Some fabric modules like tcm_loop can release
+                * their internally allocated I/O reference now and
+                * struct se_cmd now.
+                *
+                * Fabric modules are expected to return '1' here if the
+                * se_cmd being passed is released at this point,
+                * or zero if not being released.
+                */
+               if (cmd->se_tfo->check_stop_free != NULL) {
+                       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+                       return cmd->se_tfo->check_stop_free(cmd);
                }
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+       }
 
-               return 0;
-       } else if (t_state)
-               cmd->t_state = t_state;
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
        return 0;
 }
 
 static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
 {
-       return transport_cmd_check_stop(cmd, 2, 0);
+       return transport_cmd_check_stop(cmd, true);
 }
 
 static void transport_lun_remove_cmd(struct se_cmd *cmd)
@@ -591,79 +556,8 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 
        if (transport_cmd_check_stop_to_fabric(cmd))
                return;
-       if (remove) {
-               transport_remove_cmd_from_queue(cmd);
+       if (remove)
                transport_put_cmd(cmd);
-       }
-}
-
-static void transport_add_cmd_to_queue(struct se_cmd *cmd, int t_state,
-               bool at_head)
-{
-       struct se_device *dev = cmd->se_dev;
-       struct se_queue_obj *qobj = &dev->dev_queue_obj;
-       unsigned long flags;
-
-       if (t_state) {
-               spin_lock_irqsave(&cmd->t_state_lock, flags);
-               cmd->t_state = t_state;
-               cmd->transport_state |= CMD_T_ACTIVE;
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-       }
-
-       spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
-
-       /* If the cmd is already on the list, remove it before we add it */
-       if (!list_empty(&cmd->se_queue_node))
-               list_del(&cmd->se_queue_node);
-       else
-               atomic_inc(&qobj->queue_cnt);
-
-       if (at_head)
-               list_add(&cmd->se_queue_node, &qobj->qobj_list);
-       else
-               list_add_tail(&cmd->se_queue_node, &qobj->qobj_list);
-       cmd->transport_state |= CMD_T_QUEUED;
-       spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-
-       wake_up_interruptible(&qobj->thread_wq);
-}
-
-static struct se_cmd *
-transport_get_cmd_from_queue(struct se_queue_obj *qobj)
-{
-       struct se_cmd *cmd;
-       unsigned long flags;
-
-       spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
-       if (list_empty(&qobj->qobj_list)) {
-               spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-               return NULL;
-       }
-       cmd = list_first_entry(&qobj->qobj_list, struct se_cmd, se_queue_node);
-
-       cmd->transport_state &= ~CMD_T_QUEUED;
-       list_del_init(&cmd->se_queue_node);
-       atomic_dec(&qobj->queue_cnt);
-       spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-
-       return cmd;
-}
-
-static void transport_remove_cmd_from_queue(struct se_cmd *cmd)
-{
-       struct se_queue_obj *qobj = &cmd->se_dev->dev_queue_obj;
-       unsigned long flags;
-
-       spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
-       if (!(cmd->transport_state & CMD_T_QUEUED)) {
-               spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
-               return;
-       }
-       cmd->transport_state &= ~CMD_T_QUEUED;
-       atomic_dec(&qobj->queue_cnt);
-       list_del_init(&cmd->se_queue_node);
-       spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
 }
 
 static void target_complete_failure_work(struct work_struct *work)
@@ -742,68 +636,11 @@ static void target_add_to_state_list(struct se_cmd *cmd)
        spin_unlock_irqrestore(&dev->execute_task_lock, flags);
 }
 
-static void __target_add_to_execute_list(struct se_cmd *cmd)
-{
-       struct se_device *dev = cmd->se_dev;
-       bool head_of_queue = false;
-
-       if (!list_empty(&cmd->execute_list))
-               return;
-
-       if (dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED &&
-           cmd->sam_task_attr == MSG_HEAD_TAG)
-               head_of_queue = true;
-
-       if (head_of_queue)
-               list_add(&cmd->execute_list, &dev->execute_list);
-       else
-               list_add_tail(&cmd->execute_list, &dev->execute_list);
-
-       atomic_inc(&dev->execute_tasks);
-
-       if (cmd->state_active)
-               return;
-
-       if (head_of_queue)
-               list_add(&cmd->state_list, &dev->state_list);
-       else
-               list_add_tail(&cmd->state_list, &dev->state_list);
-
-       cmd->state_active = true;
-}
-
-static void target_add_to_execute_list(struct se_cmd *cmd)
-{
-       unsigned long flags;
-       struct se_device *dev = cmd->se_dev;
-
-       spin_lock_irqsave(&dev->execute_task_lock, flags);
-       __target_add_to_execute_list(cmd);
-       spin_unlock_irqrestore(&dev->execute_task_lock, flags);
-}
-
-void __target_remove_from_execute_list(struct se_cmd *cmd)
-{
-       list_del_init(&cmd->execute_list);
-       atomic_dec(&cmd->se_dev->execute_tasks);
-}
-
-static void target_remove_from_execute_list(struct se_cmd *cmd)
-{
-       struct se_device *dev = cmd->se_dev;
-       unsigned long flags;
-
-       if (WARN_ON(list_empty(&cmd->execute_list)))
-               return;
-
-       spin_lock_irqsave(&dev->execute_task_lock, flags);
-       __target_remove_from_execute_list(cmd);
-       spin_unlock_irqrestore(&dev->execute_task_lock, flags);
-}
-
 /*
  * Handle QUEUE_FULL / -EAGAIN and -ENOMEM status
  */
+static void transport_write_pending_qf(struct se_cmd *cmd);
+static void transport_complete_qf(struct se_cmd *cmd);
 
 static void target_qf_do_work(struct work_struct *work)
 {
@@ -827,7 +664,10 @@ static void target_qf_do_work(struct work_struct *work)
                        (cmd->t_state == TRANSPORT_COMPLETE_QF_WP) ? "WRITE_PENDING"
                        : "UNKNOWN");
 
-               transport_add_cmd_to_queue(cmd, cmd->t_state, true);
+               if (cmd->t_state == TRANSPORT_COMPLETE_QF_WP)
+                       transport_write_pending_qf(cmd);
+               else if (cmd->t_state == TRANSPORT_COMPLETE_QF_OK)
+                       transport_complete_qf(cmd);
        }
 }
 
@@ -874,8 +714,7 @@ void transport_dump_dev_state(
                break;
        }
 
-       *bl += sprintf(b + *bl, "  Execute/Max Queue Depth: %d/%d",
-               atomic_read(&dev->execute_tasks), dev->queue_depth);
+       *bl += sprintf(b + *bl, "  Max Queue Depth: %d", dev->queue_depth);
        *bl += sprintf(b + *bl, "  SectorSize: %u  HwMaxSectors: %u\n",
                dev->se_sub_dev->se_dev_attrib.block_size,
                dev->se_sub_dev->se_dev_attrib.hw_max_sectors);
@@ -1212,7 +1051,6 @@ struct se_device *transport_add_device_to_core_hba(
                return NULL;
        }
 
-       transport_init_queue_obj(&dev->dev_queue_obj);
        dev->dev_flags          = device_flags;
        dev->dev_status         |= TRANSPORT_DEVICE_DEACTIVATED;
        dev->dev_ptr            = transport_dev;
@@ -1222,7 +1060,6 @@ struct se_device *transport_add_device_to_core_hba(
        INIT_LIST_HEAD(&dev->dev_list);
        INIT_LIST_HEAD(&dev->dev_sep_list);
        INIT_LIST_HEAD(&dev->dev_tmr_list);
-       INIT_LIST_HEAD(&dev->execute_list);
        INIT_LIST_HEAD(&dev->delayed_cmd_list);
        INIT_LIST_HEAD(&dev->state_list);
        INIT_LIST_HEAD(&dev->qf_cmd_list);
@@ -1261,17 +1098,17 @@ struct se_device *transport_add_device_to_core_hba(
         * Setup the Asymmetric Logical Unit Assignment for struct se_device
         */
        if (core_setup_alua(dev, force_pt) < 0)
-               goto out;
+               goto err_dev_list;
 
        /*
         * Startup the struct se_device processing thread
         */
-       dev->process_thread = kthread_run(transport_processing_thread, dev,
-                                         "LIO_%s", dev->transport->name);
-       if (IS_ERR(dev->process_thread)) {
-               pr_err("Unable to create kthread: LIO_%s\n",
+       dev->tmr_wq = alloc_workqueue("tmr-%s", WQ_MEM_RECLAIM | WQ_UNBOUND, 1,
+                                     dev->transport->name);
+       if (!dev->tmr_wq) {
+               pr_err("Unable to create tmr workqueue for %s\n",
                        dev->transport->name);
-               goto out;
+               goto err_dev_list;
        }
        /*
         * Setup work_queue for QUEUE_FULL
@@ -1289,7 +1126,7 @@ struct se_device *transport_add_device_to_core_hba(
                if (!inquiry_prod || !inquiry_rev) {
                        pr_err("All non TCM/pSCSI plugins require"
                                " INQUIRY consts\n");
-                       goto out;
+                       goto err_wq;
                }
 
                strncpy(&dev->se_sub_dev->t10_wwn.vendor[0], "LIO-ORG", 8);
@@ -1299,9 +1136,10 @@ struct se_device *transport_add_device_to_core_hba(
        scsi_dump_inquiry(dev);
 
        return dev;
-out:
-       kthread_stop(dev->process_thread);
 
+err_wq:
+       destroy_workqueue(dev->tmr_wq);
+err_dev_list:
        spin_lock(&hba->device_lock);
        list_del(&dev->dev_list);
        hba->dev_count--;
@@ -1315,35 +1153,54 @@ out:
 }
 EXPORT_SYMBOL(transport_add_device_to_core_hba);
 
-/*     transport_generic_prepare_cdb():
- *
- *     Since the Initiator sees iSCSI devices as LUNs,  the SCSI CDB will
- *     contain the iSCSI LUN in bits 7-5 of byte 1 as per SAM-2.
- *     The point of this is since we are mapping iSCSI LUNs to
- *     SCSI Target IDs having a non-zero LUN in the CDB will throw the
- *     devices and HBAs for a loop.
- */
-static inline void transport_generic_prepare_cdb(
-       unsigned char *cdb)
+int target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
 {
-       switch (cdb[0]) {
-       case READ_10: /* SBC - RDProtect */
-       case READ_12: /* SBC - RDProtect */
-       case READ_16: /* SBC - RDProtect */
-       case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
-       case VERIFY: /* SBC - VRProtect */
-       case VERIFY_16: /* SBC - VRProtect */
-       case WRITE_VERIFY: /* SBC - VRProtect */
-       case WRITE_VERIFY_12: /* SBC - VRProtect */
-       case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
-               break;
-       default:
-               cdb[1] &= 0x1f; /* clear logical unit number */
-               break;
+       struct se_device *dev = cmd->se_dev;
+
+       if (cmd->unknown_data_length) {
+               cmd->data_length = size;
+       } else if (size != cmd->data_length) {
+               pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
+                       " %u does not match SCSI CDB Length: %u for SAM Opcode:"
+                       " 0x%02x\n", cmd->se_tfo->get_fabric_name(),
+                               cmd->data_length, size, cmd->t_task_cdb[0]);
+
+               cmd->cmd_spdtl = size;
+
+               if (cmd->data_direction == DMA_TO_DEVICE) {
+                       pr_err("Rejecting underflow/overflow"
+                                       " WRITE data\n");
+                       goto out_invalid_cdb_field;
+               }
+               /*
+                * Reject READ_* or WRITE_* with overflow/underflow for
+                * type SCF_SCSI_DATA_CDB.
+                */
+               if (dev->se_sub_dev->se_dev_attrib.block_size != 512)  {
+                       pr_err("Failing OVERFLOW/UNDERFLOW for LBA op"
+                               " CDB on non 512-byte sector setup subsystem"
+                               " plugin: %s\n", dev->transport->name);
+                       /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
+                       goto out_invalid_cdb_field;
+               }
+
+               if (size > cmd->data_length) {
+                       cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
+                       cmd->residual_count = (size - cmd->data_length);
+               } else {
+                       cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
+                       cmd->residual_count = (cmd->data_length - size);
+               }
+               cmd->data_length = size;
        }
-}
 
-static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *);
+       return 0;
+
+out_invalid_cdb_field:
+       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+       cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+       return -EINVAL;
+}
 
 /*
  * Used by fabric modules containing a local struct se_cmd within their
@@ -1361,9 +1218,7 @@ void transport_init_se_cmd(
        INIT_LIST_HEAD(&cmd->se_lun_node);
        INIT_LIST_HEAD(&cmd->se_delayed_node);
        INIT_LIST_HEAD(&cmd->se_qf_node);
-       INIT_LIST_HEAD(&cmd->se_queue_node);
        INIT_LIST_HEAD(&cmd->se_cmd_list);
-       INIT_LIST_HEAD(&cmd->execute_list);
        INIT_LIST_HEAD(&cmd->state_list);
        init_completion(&cmd->transport_lun_fe_stop_comp);
        init_completion(&cmd->transport_lun_stop_comp);
@@ -1418,9 +1273,12 @@ int target_setup_cmd_from_cdb(
        struct se_cmd *cmd,
        unsigned char *cdb)
 {
+       struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
+       u32 pr_reg_type = 0;
+       u8 alua_ascq = 0;
+       unsigned long flags;
        int ret;
 
-       transport_generic_prepare_cdb(cdb);
        /*
         * Ensure that the received CDB is less than the max (252 + 8) bytes
         * for VARIABLE_LENGTH_CMD
@@ -1457,15 +1315,66 @@ int target_setup_cmd_from_cdb(
         * Copy the original CDB into cmd->
         */
        memcpy(cmd->t_task_cdb, cdb, scsi_command_size(cdb));
+
+       /*
+        * Check for an existing UNIT ATTENTION condition
+        */
+       if (core_scsi3_ua_check(cmd, cdb) < 0) {
+               cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
+               return -EINVAL;
+       }
+
+       ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq);
+       if (ret != 0) {
+               /*
+                * Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
+                * The ALUA additional sense code qualifier (ASCQ) is determined
+                * by the ALUA primary or secondary access state..
+                */
+               if (ret > 0) {
+                       pr_debug("[%s]: ALUA TG Port not available, "
+                               "SenseKey: NOT_READY, ASC/ASCQ: "
+                               "0x04/0x%02x\n",
+                               cmd->se_tfo->get_fabric_name(), alua_ascq);
+
+                       transport_set_sense_codes(cmd, 0x04, alua_ascq);
+                       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+                       cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY;
+                       return -EINVAL;
+               }
+               cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+               return -EINVAL;
+       }
+
        /*
-        * Setup the received CDB based on SCSI defined opcodes and
-        * perform unit attention, persistent reservations and ALUA
-        * checks for virtual device backends.  The cmd->t_task_cdb
-        * pointer is expected to be setup before we reach this point.
+        * Check status for SPC-3 Persistent Reservations
         */
-       ret = transport_generic_cmd_sequencer(cmd, cdb);
+       if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type)) {
+               if (su_dev->t10_pr.pr_ops.t10_seq_non_holder(
+                                       cmd, cdb, pr_reg_type) != 0) {
+                       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+                       cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
+                       cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+                       cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
+                       return -EBUSY;
+               }
+               /*
+                * This means the CDB is allowed for the SCSI Initiator port
+                * when said port is *NOT* holding the legacy SPC-2 or
+                * SPC-3 Persistent Reservation.
+                */
+       }
+
+       ret = cmd->se_dev->transport->parse_cdb(cmd);
        if (ret < 0)
                return ret;
+
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
        /*
         * Check for SAM Task Attribute Emulation
         */
@@ -1503,10 +1412,9 @@ int transport_handle_cdb_direct(
                return -EINVAL;
        }
        /*
-        * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE following
-        * transport_generic_handle_cdb*() -> transport_add_cmd_to_queue()
-        * in existing usage to ensure that outstanding descriptors are handled
-        * correctly during shutdown via transport_wait_for_tasks()
+        * Set TRANSPORT_NEW_CMD state and CMD_T_ACTIVE to ensure that
+        * outstanding descriptors are handled correctly during shutdown via
+        * transport_wait_for_tasks()
         *
         * Also, we don't take cmd->t_state_lock here as we only expect
         * this to be called for initial descriptor submission.
@@ -1540,10 +1448,14 @@ EXPORT_SYMBOL(transport_handle_cdb_direct);
  * @data_dir: DMA data direction
  * @flags: flags for command submission from target_sc_flags_tables
  *
+ * Returns non zero to signal active I/O shutdown failure.  All other
+ * setup exceptions will be returned as a SCSI CHECK_CONDITION response,
+ * but still return zero here.
+ *
  * This may only be called from process context, and also currently
  * assumes internal allocation of fabric payload buffer by target-core.
  **/
-void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
+int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
                unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
                u32 data_length, int task_attr, int data_dir, int flags)
 {
@@ -1569,7 +1481,9 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
         * for fabrics using TARGET_SCF_ACK_KREF that expect a second
         * kref_put() to happen during fabric packet acknowledgement.
         */
-       target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF));
+       rc = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF));
+       if (rc)
+               return rc;
        /*
         * Signal bidirectional data payloads to target-core
         */
@@ -1582,16 +1496,13 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
                transport_send_check_condition_and_sense(se_cmd,
                                se_cmd->scsi_sense_reason, 0);
                target_put_sess_cmd(se_sess, se_cmd);
-               return;
+               return 0;
        }
-       /*
-        * Sanitize CDBs via transport_generic_cmd_sequencer() and
-        * allocate the necessary tasks to complete the received CDB+data
-        */
+
        rc = target_setup_cmd_from_cdb(se_cmd, cdb);
        if (rc != 0) {
                transport_generic_request_failure(se_cmd);
-               return;
+               return 0;
        }
 
        /*
@@ -1600,14 +1511,8 @@ void target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
         */
        core_alua_check_nonop_delay(se_cmd);
 
-       /*
-        * Dispatch se_cmd descriptor to se_lun->lun_se_dev backend
-        * for immediate execution of READs, otherwise wait for
-        * transport_generic_handle_data() to be called for WRITEs
-        * when fabric has filled the incoming buffer.
-        */
        transport_handle_cdb_direct(se_cmd);
-       return;
+       return 0;
 }
 EXPORT_SYMBOL(target_submit_cmd);
 
@@ -1662,7 +1567,11 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
                se_cmd->se_tmr_req->ref_task_tag = tag;
 
        /* See target_submit_cmd for commentary */
-       target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF));
+       ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF));
+       if (ret) {
+               core_tmr_release_req(se_cmd->se_tmr_req);
+               return ret;
+       }
 
        ret = transport_lookup_tmr_lun(se_cmd, unpacked_lun);
        if (ret) {
@@ -1679,67 +1588,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
 }
 EXPORT_SYMBOL(target_submit_tmr);
 
-/*
- * Used by fabric module frontends defining a TFO->new_cmd_map() caller
- * to  queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to
- * complete setup in TCM process context w/ TFO->new_cmd_map().
- */
-int transport_generic_handle_cdb_map(
-       struct se_cmd *cmd)
-{
-       if (!cmd->se_lun) {
-               dump_stack();
-               pr_err("cmd->se_lun is NULL\n");
-               return -EINVAL;
-       }
-
-       transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP, false);
-       return 0;
-}
-EXPORT_SYMBOL(transport_generic_handle_cdb_map);
-
-/*     transport_generic_handle_data():
- *
- *
- */
-int transport_generic_handle_data(
-       struct se_cmd *cmd)
-{
-       /*
-        * For the software fabric case, then we assume the nexus is being
-        * failed/shutdown when signals are pending from the kthread context
-        * caller, so we return a failure.  For the HW target mode case running
-        * in interrupt code, the signal_pending() check is skipped.
-        */
-       if (!in_interrupt() && signal_pending(current))
-               return -EPERM;
-       /*
-        * If the received CDB has aleady been ABORTED by the generic
-        * target engine, we now call transport_check_aborted_status()
-        * to queue any delated TASK_ABORTED status for the received CDB to the
-        * fabric module as we are expecting no further incoming DATA OUT
-        * sequences at this point.
-        */
-       if (transport_check_aborted_status(cmd, 1) != 0)
-               return 0;
-
-       transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE, false);
-       return 0;
-}
-EXPORT_SYMBOL(transport_generic_handle_data);
-
-/*     transport_generic_handle_tmr():
- *
- *
- */
-int transport_generic_handle_tmr(
-       struct se_cmd *cmd)
-{
-       transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR, false);
-       return 0;
-}
-EXPORT_SYMBOL(transport_generic_handle_tmr);
-
 /*
  * If the cmd is active, request it to be stopped and sleep until it
  * has completed.
@@ -1797,6 +1645,7 @@ void transport_generic_request_failure(struct se_cmd *cmd)
        case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
        case TCM_UNKNOWN_MODE_PAGE:
        case TCM_WRITE_PROTECTED:
+       case TCM_ADDRESS_OUT_OF_RANGE:
        case TCM_CHECK_CONDITION_ABORT_CMD:
        case TCM_CHECK_CONDITION_UNIT_ATTENTION:
        case TCM_CHECK_CONDITION_NOT_READY:
@@ -1832,13 +1681,7 @@ void transport_generic_request_failure(struct se_cmd *cmd)
                cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
                break;
        }
-       /*
-        * If a fabric does not define a cmd->se_tfo->new_cmd_map caller,
-        * make the call to transport_send_check_condition_and_sense()
-        * directly.  Otherwise expect the fabric to make the call to
-        * transport_send_check_condition_and_sense() after handling
-        * possible unsoliticied write data payloads.
-        */
+
        ret = transport_send_check_condition_and_sense(cmd,
                        cmd->scsi_sense_reason, 0);
        if (ret == -EAGAIN || ret == -ENOMEM)
@@ -1856,1193 +1699,204 @@ queue_full:
 }
 EXPORT_SYMBOL(transport_generic_request_failure);
 
-static inline u32 transport_lba_21(unsigned char *cdb)
-{
-       return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
-}
-
-static inline u32 transport_lba_32(unsigned char *cdb)
-{
-       return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
-}
-
-static inline unsigned long long transport_lba_64(unsigned char *cdb)
-{
-       unsigned int __v1, __v2;
-
-       __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
-       __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
-
-       return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
-}
-
-/*
- * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs
- */
-static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
-{
-       unsigned int __v1, __v2;
-
-       __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15];
-       __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19];
-
-       return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
-}
-
-static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&se_cmd->t_state_lock, flags);
-       se_cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
-       spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
-}
-
-/*
- * Called from Fabric Module context from transport_execute_tasks()
- *
- * The return of this function determins if the tasks from struct se_cmd
- * get added to the execution queue in transport_execute_tasks(),
- * or are added to the delayed or ordered lists here.
- */
-static inline int transport_execute_task_attr(struct se_cmd *cmd)
+static void __target_execute_cmd(struct se_cmd *cmd)
 {
-       if (cmd->se_dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
-               return 1;
-       /*
-        * Check for the existence of HEAD_OF_QUEUE, and if true return 1
-        * to allow the passed struct se_cmd list of tasks to the front of the list.
-        */
-        if (cmd->sam_task_attr == MSG_HEAD_TAG) {
-               pr_debug("Added HEAD_OF_QUEUE for CDB:"
-                       " 0x%02x, se_ordered_id: %u\n",
-                       cmd->t_task_cdb[0],
-                       cmd->se_ordered_id);
-               return 1;
-       } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) {
-               atomic_inc(&cmd->se_dev->dev_ordered_sync);
-               smp_mb__after_atomic_inc();
+       int error = 0;
 
-               pr_debug("Added ORDERED for CDB: 0x%02x to ordered"
-                               " list, se_ordered_id: %u\n",
-                               cmd->t_task_cdb[0],
-                               cmd->se_ordered_id);
-               /*
-                * Add ORDERED command to tail of execution queue if
-                * no other older commands exist that need to be
-                * completed first.
-                */
-               if (!atomic_read(&cmd->se_dev->simple_cmds))
-                       return 1;
-       } else {
-               /*
-                * For SIMPLE and UNTAGGED Task Attribute commands
-                */
-               atomic_inc(&cmd->se_dev->simple_cmds);
-               smp_mb__after_atomic_inc();
-       }
-       /*
-        * Otherwise if one or more outstanding ORDERED task attribute exist,
-        * add the dormant task(s) built for the passed struct se_cmd to the
-        * execution queue and become in Active state for this struct se_device.
-        */
-       if (atomic_read(&cmd->se_dev->dev_ordered_sync) != 0) {
-               /*
-                * Otherwise, add cmd w/ tasks to delayed cmd queue that
-                * will be drained upon completion of HEAD_OF_QUEUE task.
-                */
-               spin_lock(&cmd->se_dev->delayed_cmd_lock);
-               cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR;
-               list_add_tail(&cmd->se_delayed_node,
-                               &cmd->se_dev->delayed_cmd_list);
-               spin_unlock(&cmd->se_dev->delayed_cmd_lock);
-
-               pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to"
-                       " delayed CMD list, se_ordered_id: %u\n",
-                       cmd->t_task_cdb[0], cmd->sam_task_attr,
-                       cmd->se_ordered_id);
-               /*
-                * Return zero to let transport_execute_tasks() know
-                * not to add the delayed tasks to the execution list.
-                */
-               return 0;
-       }
-       /*
-        * Otherwise, no ORDERED task attributes exist..
-        */
-       return 1;
-}
-
-/*
- * Called from fabric module context in transport_generic_new_cmd() and
- * transport_generic_process_write()
- */
-static void transport_execute_tasks(struct se_cmd *cmd)
-{
-       int add_tasks;
-       struct se_device *se_dev = cmd->se_dev;
-       /*
-        * Call transport_cmd_check_stop() to see if a fabric exception
-        * has occurred that prevents execution.
-        */
-       if (!transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING)) {
-               /*
-                * Check for SAM Task Attribute emulation and HEAD_OF_QUEUE
-                * attribute for the tasks of the received struct se_cmd CDB
-                */
-               add_tasks = transport_execute_task_attr(cmd);
-               if (add_tasks) {
-                       __transport_execute_tasks(se_dev, cmd);
-                       return;
-               }
-       }
-       __transport_execute_tasks(se_dev, NULL);
-}
-
-static int __transport_execute_tasks(struct se_device *dev, struct se_cmd *new_cmd)
-{
-       int error;
-       struct se_cmd *cmd = NULL;
-       unsigned long flags;
-
-check_depth:
-       spin_lock_irq(&dev->execute_task_lock);
-       if (new_cmd != NULL)
-               __target_add_to_execute_list(new_cmd);
-
-       if (list_empty(&dev->execute_list)) {
-               spin_unlock_irq(&dev->execute_task_lock);
-               return 0;
-       }
-       cmd = list_first_entry(&dev->execute_list, struct se_cmd, execute_list);
-       __target_remove_from_execute_list(cmd);
-       spin_unlock_irq(&dev->execute_task_lock);
-
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
-       cmd->transport_state |= CMD_T_BUSY;
-       cmd->transport_state |= CMD_T_SENT;
-
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+       spin_lock_irq(&cmd->t_state_lock);
+       cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT);
+       spin_unlock_irq(&cmd->t_state_lock);
 
        if (cmd->execute_cmd)
                error = cmd->execute_cmd(cmd);
-       else {
-               error = dev->transport->execute_cmd(cmd, cmd->t_data_sg,
-                               cmd->t_data_nents, cmd->data_direction);
-       }
 
-       if (error != 0) {
-               spin_lock_irqsave(&cmd->t_state_lock, flags);
-               cmd->transport_state &= ~CMD_T_BUSY;
-               cmd->transport_state &= ~CMD_T_SENT;
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+       if (error) {
+               spin_lock_irq(&cmd->t_state_lock);
+               cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
+               spin_unlock_irq(&cmd->t_state_lock);
 
                transport_generic_request_failure(cmd);
        }
-
-       new_cmd = NULL;
-       goto check_depth;
-
-       return 0;
 }
 
-static inline u32 transport_get_sectors_6(
-       unsigned char *cdb,
-       struct se_cmd *cmd,
-       int *ret)
+void target_execute_cmd(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
 
        /*
-        * Assume TYPE_DISK for non struct se_device objects.
-        * Use 8-bit sector value.
-        */
-       if (!dev)
-               goto type_disk;
-
-       /*
-        * Use 24-bit allocation length for TYPE_TAPE.
-        */
-       if (dev->transport->get_device_type(dev) == TYPE_TAPE)
-               return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4];
-
-       /*
-        * Everything else assume TYPE_DISK Sector CDB location.
-        * Use 8-bit sector value.  SBC-3 says:
-        *
-        *   A TRANSFER LENGTH field set to zero specifies that 256
-        *   logical blocks shall be written.  Any other value
-        *   specifies the number of logical blocks that shall be
-        *   written.
+        * If the received CDB has aleady been aborted stop processing it here.
         */
-type_disk:
-       return cdb[4] ? : 256;
-}
-
-static inline u32 transport_get_sectors_10(
-       unsigned char *cdb,
-       struct se_cmd *cmd,
-       int *ret)
-{
-       struct se_device *dev = cmd->se_dev;
+       if (transport_check_aborted_status(cmd, 1))
+               return;
 
        /*
-        * Assume TYPE_DISK for non struct se_device objects.
-        * Use 16-bit sector value.
+        * Determine if IOCTL context caller in requesting the stopping of this
+        * command for LUN shutdown purposes.
         */
-       if (!dev)
-               goto type_disk;
+       spin_lock_irq(&cmd->t_state_lock);
+       if (cmd->transport_state & CMD_T_LUN_STOP) {
+               pr_debug("%s:%d CMD_T_LUN_STOP for ITT: 0x%08x\n",
+                       __func__, __LINE__, cmd->se_tfo->get_task_tag(cmd));
 
-       /*
-        * XXX_10 is not defined in SSC, throw an exception
-        */
-       if (dev->transport->get_device_type(dev) == TYPE_TAPE) {
-               *ret = -EINVAL;
-               return 0;
+               cmd->transport_state &= ~CMD_T_ACTIVE;
+               spin_unlock_irq(&cmd->t_state_lock);
+               complete(&cmd->transport_lun_stop_comp);
+               return;
        }
-
-       /*
-        * Everything else assume TYPE_DISK Sector CDB location.
-        * Use 16-bit sector value.
-        */
-type_disk:
-       return (u32)(cdb[7] << 8) + cdb[8];
-}
-
-static inline u32 transport_get_sectors_12(
-       unsigned char *cdb,
-       struct se_cmd *cmd,
-       int *ret)
-{
-       struct se_device *dev = cmd->se_dev;
-
        /*
-        * Assume TYPE_DISK for non struct se_device objects.
-        * Use 32-bit sector value.
+        * Determine if frontend context caller is requesting the stopping of
+        * this command for frontend exceptions.
         */
-       if (!dev)
-               goto type_disk;
+       if (cmd->transport_state & CMD_T_STOP) {
+               pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n",
+                       __func__, __LINE__,
+                       cmd->se_tfo->get_task_tag(cmd));
 
-       /*
-        * XXX_12 is not defined in SSC, throw an exception
-        */
-       if (dev->transport->get_device_type(dev) == TYPE_TAPE) {
-               *ret = -EINVAL;
-               return 0;
+               spin_unlock_irq(&cmd->t_state_lock);
+               complete(&cmd->t_transport_stop_comp);
+               return;
        }
 
-       /*
-        * Everything else assume TYPE_DISK Sector CDB location.
-        * Use 32-bit sector value.
-        */
-type_disk:
-       return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
-}
+       cmd->t_state = TRANSPORT_PROCESSING;
+       spin_unlock_irq(&cmd->t_state_lock);
 
-static inline u32 transport_get_sectors_16(
-       unsigned char *cdb,
-       struct se_cmd *cmd,
-       int *ret)
-{
-       struct se_device *dev = cmd->se_dev;
-
-       /*
-        * Assume TYPE_DISK for non struct se_device objects.
-        * Use 32-bit sector value.
-        */
-       if (!dev)
-               goto type_disk;
+       if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
+               goto execute;
 
        /*
-        * Use 24-bit allocation length for TYPE_TAPE.
-        */
-       if (dev->transport->get_device_type(dev) == TYPE_TAPE)
-               return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14];
-
-type_disk:
-       return (u32)(cdb[10] << 24) + (cdb[11] << 16) +
-                   (cdb[12] << 8) + cdb[13];
-}
-
-/*
- * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants
- */
-static inline u32 transport_get_sectors_32(
-       unsigned char *cdb,
-       struct se_cmd *cmd,
-       int *ret)
-{
-       /*
-        * Assume TYPE_DISK for non struct se_device objects.
-        * Use 32-bit sector value.
+        * Check for the existence of HEAD_OF_QUEUE, and if true return 1
+        * to allow the passed struct se_cmd list of tasks to the front of the list.
         */
-       return (u32)(cdb[28] << 24) + (cdb[29] << 16) +
-                   (cdb[30] << 8) + cdb[31];
+       switch (cmd->sam_task_attr) {
+       case MSG_HEAD_TAG:
+               pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x, "
+                        "se_ordered_id: %u\n",
+                        cmd->t_task_cdb[0], cmd->se_ordered_id);
+               goto execute;
+       case MSG_ORDERED_TAG:
+               atomic_inc(&dev->dev_ordered_sync);
+               smp_mb__after_atomic_inc();
 
-}
+               pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, "
+                        " se_ordered_id: %u\n",
+                        cmd->t_task_cdb[0], cmd->se_ordered_id);
 
-static inline u32 transport_get_size(
-       u32 sectors,
-       unsigned char *cdb,
-       struct se_cmd *cmd)
-{
-       struct se_device *dev = cmd->se_dev;
-
-       if (dev->transport->get_device_type(dev) == TYPE_TAPE) {
-               if (cdb[1] & 1) { /* sectors */
-                       return dev->se_sub_dev->se_dev_attrib.block_size * sectors;
-               } else /* bytes */
-                       return sectors;
+               /*
+                * Execute an ORDERED command if no other older commands
+                * exist that need to be completed first.
+                */
+               if (!atomic_read(&dev->simple_cmds))
+                       goto execute;
+               break;
+       default:
+               /*
+                * For SIMPLE and UNTAGGED Task Attribute commands
+                */
+               atomic_inc(&dev->simple_cmds);
+               smp_mb__after_atomic_inc();
+               break;
        }
 
-       pr_debug("Returning block_size: %u, sectors: %u == %u for"
-               " %s object\n", dev->se_sub_dev->se_dev_attrib.block_size,
-               sectors, dev->se_sub_dev->se_dev_attrib.block_size * sectors,
-               dev->transport->name);
-
-       return dev->se_sub_dev->se_dev_attrib.block_size * sectors;
-}
+       if (atomic_read(&dev->dev_ordered_sync) != 0) {
+               spin_lock(&dev->delayed_cmd_lock);
+               list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list);
+               spin_unlock(&dev->delayed_cmd_lock);
 
-static void transport_xor_callback(struct se_cmd *cmd)
-{
-       unsigned char *buf, *addr;
-       struct scatterlist *sg;
-       unsigned int offset;
-       int i;
-       int count;
-       /*
-        * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
-        *
-        * 1) read the specified logical block(s);
-        * 2) transfer logical blocks from the data-out buffer;
-        * 3) XOR the logical blocks transferred from the data-out buffer with
-        *    the logical blocks read, storing the resulting XOR data in a buffer;
-        * 4) if the DISABLE WRITE bit is set to zero, then write the logical
-        *    blocks transferred from the data-out buffer; and
-        * 5) transfer the resulting XOR data to the data-in buffer.
-        */
-       buf = kmalloc(cmd->data_length, GFP_KERNEL);
-       if (!buf) {
-               pr_err("Unable to allocate xor_callback buf\n");
+               pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to"
+                       " delayed CMD list, se_ordered_id: %u\n",
+                       cmd->t_task_cdb[0], cmd->sam_task_attr,
+                       cmd->se_ordered_id);
                return;
        }
-       /*
-        * Copy the scatterlist WRITE buffer located at cmd->t_data_sg
-        * into the locally allocated *buf
-        */
-       sg_copy_to_buffer(cmd->t_data_sg,
-                         cmd->t_data_nents,
-                         buf,
-                         cmd->data_length);
 
+execute:
        /*
-        * Now perform the XOR against the BIDI read memory located at
-        * cmd->t_mem_bidi_list
+        * Otherwise, no ORDERED task attributes exist..
         */
-
-       offset = 0;
-       for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) {
-               addr = kmap_atomic(sg_page(sg));
-               if (!addr)
-                       goto out;
-
-               for (i = 0; i < sg->length; i++)
-                       *(addr + sg->offset + i) ^= *(buf + offset + i);
-
-               offset += sg->length;
-               kunmap_atomic(addr);
-       }
-
-out:
-       kfree(buf);
+       __target_execute_cmd(cmd);
 }
+EXPORT_SYMBOL(target_execute_cmd);
 
 /*
  * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd
  */
 static int transport_get_sense_data(struct se_cmd *cmd)
 {
-       unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
-       struct se_device *dev = cmd->se_dev;
-       unsigned long flags;
-       u32 offset = 0;
-
-       WARN_ON(!cmd->se_lun);
-
-       if (!dev)
-               return 0;
-
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
-       if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-               return 0;
-       }
-
-       if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
-               goto out;
-
-       if (!dev->transport->get_sense_buffer) {
-               pr_err("dev->transport->get_sense_buffer is NULL\n");
-               goto out;
-       }
-
-       sense_buffer = dev->transport->get_sense_buffer(cmd);
-       if (!sense_buffer) {
-               pr_err("ITT 0x%08x cmd %p: Unable to locate"
-                       " sense buffer for task with sense\n",
-                       cmd->se_tfo->get_task_tag(cmd), cmd);
-               goto out;
-       }
-
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
-       offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
-
-       memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER);
-
-       /* Automatically padded */
-       cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
-
-       pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n",
-               dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
-       return 0;
-
-out:
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-       return -1;
-}
-
-static inline long long transport_dev_end_lba(struct se_device *dev)
-{
-       return dev->transport->get_blocks(dev) + 1;
-}
-
-static int transport_cmd_get_valid_sectors(struct se_cmd *cmd)
-{
-       struct se_device *dev = cmd->se_dev;
-       u32 sectors;
-
-       if (dev->transport->get_device_type(dev) != TYPE_DISK)
-               return 0;
-
-       sectors = (cmd->data_length / dev->se_sub_dev->se_dev_attrib.block_size);
-
-       if ((cmd->t_task_lba + sectors) > transport_dev_end_lba(dev)) {
-               pr_err("LBA: %llu Sectors: %u exceeds"
-                       " transport_dev_end_lba(): %llu\n",
-                       cmd->t_task_lba, sectors,
-                       transport_dev_end_lba(dev));
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev)
-{
-       /*
-        * Determine if the received WRITE_SAME is used to for direct
-        * passthrough into Linux/SCSI with struct request via TCM/pSCSI
-        * or we are signaling the use of internal WRITE_SAME + UNMAP=1
-        * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code.
-        */
-       int passthrough = (dev->transport->transport_type ==
-                               TRANSPORT_PLUGIN_PHBA_PDEV);
-
-       if (!passthrough) {
-               if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
-                       pr_err("WRITE_SAME PBDATA and LBDATA"
-                               " bits not supported for Block Discard"
-                               " Emulation\n");
-                       return -ENOSYS;
-               }
-               /*
-                * Currently for the emulated case we only accept
-                * tpws with the UNMAP=1 bit set.
-                */
-               if (!(flags[0] & 0x08)) {
-                       pr_err("WRITE_SAME w/o UNMAP bit not"
-                               " supported for Block Discard Emulation\n");
-                       return -ENOSYS;
-               }
-       }
-
-       return 0;
-}
-
-/*     transport_generic_cmd_sequencer():
- *
- *     Generic Command Sequencer that should work for most DAS transport
- *     drivers.
- *
- *     Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD
- *     RX Thread.
- *
- *     FIXME: Need to support other SCSI OPCODES where as well.
- */
-static int transport_generic_cmd_sequencer(
-       struct se_cmd *cmd,
-       unsigned char *cdb)
-{
-       struct se_device *dev = cmd->se_dev;
-       struct se_subsystem_dev *su_dev = dev->se_sub_dev;
-       int ret = 0, sector_ret = 0, passthrough;
-       u32 sectors = 0, size = 0, pr_reg_type = 0;
-       u16 service_action;
-       u8 alua_ascq = 0;
-       /*
-        * Check for an existing UNIT ATTENTION condition
-        */
-       if (core_scsi3_ua_check(cmd, cdb) < 0) {
-               cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-               cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
-               return -EINVAL;
-       }
-       /*
-        * Check status of Asymmetric Logical Unit Assignment port
-        */
-       ret = su_dev->t10_alua.alua_state_check(cmd, cdb, &alua_ascq);
-       if (ret != 0) {
-               /*
-                * Set SCSI additional sense code (ASC) to 'LUN Not Accessible';
-                * The ALUA additional sense code qualifier (ASCQ) is determined
-                * by the ALUA primary or secondary access state..
-                */
-               if (ret > 0) {
-                       pr_debug("[%s]: ALUA TG Port not available,"
-                               " SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n",
-                               cmd->se_tfo->get_fabric_name(), alua_ascq);
-
-                       transport_set_sense_codes(cmd, 0x04, alua_ascq);
-                       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-                       cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY;
-                       return -EINVAL;
-               }
-               goto out_invalid_cdb_field;
-       }
-       /*
-        * Check status for SPC-3 Persistent Reservations
-        */
-       if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type) != 0) {
-               if (su_dev->t10_pr.pr_ops.t10_seq_non_holder(
-                                       cmd, cdb, pr_reg_type) != 0) {
-                       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-                       cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
-                       cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
-                       cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT;
-                       return -EBUSY;
-               }
-               /*
-                * This means the CDB is allowed for the SCSI Initiator port
-                * when said port is *NOT* holding the legacy SPC-2 or
-                * SPC-3 Persistent Reservation.
-                */
-       }
-
-       /*
-        * If we operate in passthrough mode we skip most CDB emulation and
-        * instead hand the commands down to the physical SCSI device.
-        */
-       passthrough =
-               (dev->transport->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV);
-
-       switch (cdb[0]) {
-       case READ_6:
-               sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_21(cdb);
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case READ_10:
-               sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_32(cdb);
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case READ_12:
-               sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_32(cdb);
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case READ_16:
-               sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_64(cdb);
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case WRITE_6:
-               sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_21(cdb);
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case WRITE_10:
-       case WRITE_VERIFY:
-               sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_32(cdb);
-               if (cdb[1] & 0x8)
-                       cmd->se_cmd_flags |= SCF_FUA;
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case WRITE_12:
-               sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_32(cdb);
-               if (cdb[1] & 0x8)
-                       cmd->se_cmd_flags |= SCF_FUA;
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case WRITE_16:
-               sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_64(cdb);
-               if (cdb[1] & 0x8)
-                       cmd->se_cmd_flags |= SCF_FUA;
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-               break;
-       case XDWRITEREAD_10:
-               if ((cmd->data_direction != DMA_TO_DEVICE) ||
-                   !(cmd->se_cmd_flags & SCF_BIDI))
-                       goto out_invalid_cdb_field;
-               sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->t_task_lba = transport_lba_32(cdb);
-               cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-
-               /*
-                * Do now allow BIDI commands for passthrough mode.
-                */
-               if (passthrough)
-                       goto out_unsupported_cdb;
-
-               /*
-                * Setup BIDI XOR callback to be run after I/O completion.
-                */
-               cmd->transport_complete_callback = &transport_xor_callback;
-               if (cdb[1] & 0x8)
-                       cmd->se_cmd_flags |= SCF_FUA;
-               break;
-       case VARIABLE_LENGTH_CMD:
-               service_action = get_unaligned_be16(&cdb[8]);
-               switch (service_action) {
-               case XDWRITEREAD_32:
-                       sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
-                       if (sector_ret)
-                               goto out_unsupported_cdb;
-                       size = transport_get_size(sectors, cdb, cmd);
-                       /*
-                        * Use WRITE_32 and READ_32 opcodes for the emulated
-                        * XDWRITE_READ_32 logic.
-                        */
-                       cmd->t_task_lba = transport_lba_64_ext(cdb);
-                       cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
-
-                       /*
-                        * Do now allow BIDI commands for passthrough mode.
-                        */
-                       if (passthrough)
-                               goto out_unsupported_cdb;
-
-                       /*
-                        * Setup BIDI XOR callback to be run during after I/O
-                        * completion.
-                        */
-                       cmd->transport_complete_callback = &transport_xor_callback;
-                       if (cdb[1] & 0x8)
-                               cmd->se_cmd_flags |= SCF_FUA;
-                       break;
-               case WRITE_SAME_32:
-                       sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
-                       if (sector_ret)
-                               goto out_unsupported_cdb;
-
-                       if (sectors)
-                               size = transport_get_size(1, cdb, cmd);
-                       else {
-                               pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
-                                      " supported\n");
-                               goto out_invalid_cdb_field;
-                       }
-
-                       cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
-                       cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-
-                       if (target_check_write_same_discard(&cdb[10], dev) < 0)
-                               goto out_unsupported_cdb;
-                       if (!passthrough)
-                               cmd->execute_cmd = target_emulate_write_same;
-                       break;
-               default:
-                       pr_err("VARIABLE_LENGTH_CMD service action"
-                               " 0x%04x not supported\n", service_action);
-                       goto out_unsupported_cdb;
-               }
-               break;
-       case MAINTENANCE_IN:
-               if (dev->transport->get_device_type(dev) != TYPE_ROM) {
-                       /* MAINTENANCE_IN from SCC-2 */
-                       /*
-                        * Check for emulated MI_REPORT_TARGET_PGS.
-                        */
-                       if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS &&
-                           su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
-                               cmd->execute_cmd =
-                                       target_emulate_report_target_port_groups;
-                       }
-                       size = (cdb[6] << 24) | (cdb[7] << 16) |
-                              (cdb[8] << 8) | cdb[9];
-               } else {
-                       /* GPCMD_SEND_KEY from multi media commands */
-                       size = (cdb[8] << 8) + cdb[9];
-               }
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case MODE_SELECT:
-               size = cdb[4];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case MODE_SELECT_10:
-               size = (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case MODE_SENSE:
-               size = cdb[4];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_modesense;
-               break;
-       case MODE_SENSE_10:
-               size = (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_modesense;
-               break;
-       case GPCMD_READ_BUFFER_CAPACITY:
-       case GPCMD_SEND_OPC:
-       case LOG_SELECT:
-       case LOG_SENSE:
-               size = (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case READ_BLOCK_LIMITS:
-               size = READ_BLOCK_LEN;
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case GPCMD_GET_CONFIGURATION:
-       case GPCMD_READ_FORMAT_CAPACITIES:
-       case GPCMD_READ_DISC_INFO:
-       case GPCMD_READ_TRACK_RZONE_INFO:
-               size = (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case PERSISTENT_RESERVE_IN:
-               if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
-                       cmd->execute_cmd = target_scsi3_emulate_pr_in;
-               size = (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case PERSISTENT_RESERVE_OUT:
-               if (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS)
-                       cmd->execute_cmd = target_scsi3_emulate_pr_out;
-               size = (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case GPCMD_MECHANISM_STATUS:
-       case GPCMD_READ_DVD_STRUCTURE:
-               size = (cdb[8] << 8) + cdb[9];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case READ_POSITION:
-               size = READ_POSITION_LEN;
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case MAINTENANCE_OUT:
-               if (dev->transport->get_device_type(dev) != TYPE_ROM) {
-                       /* MAINTENANCE_OUT from SCC-2
-                        *
-                        * Check for emulated MO_SET_TARGET_PGS.
-                        */
-                       if (cdb[1] == MO_SET_TARGET_PGS &&
-                           su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) {
-                               cmd->execute_cmd =
-                                       target_emulate_set_target_port_groups;
-                       }
-
-                       size = (cdb[6] << 24) | (cdb[7] << 16) |
-                              (cdb[8] << 8) | cdb[9];
-               } else  {
-                       /* GPCMD_REPORT_KEY from multi media commands */
-                       size = (cdb[8] << 8) + cdb[9];
-               }
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case INQUIRY:
-               size = (cdb[3] << 8) + cdb[4];
-               /*
-                * Do implict HEAD_OF_QUEUE processing for INQUIRY.
-                * See spc4r17 section 5.3
-                */
-               if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
-                       cmd->sam_task_attr = MSG_HEAD_TAG;
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_inquiry;
-               break;
-       case READ_BUFFER:
-               size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case READ_CAPACITY:
-               size = READ_CAP_LEN;
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_readcapacity;
-               break;
-       case READ_MEDIA_SERIAL_NUMBER:
-       case SECURITY_PROTOCOL_IN:
-       case SECURITY_PROTOCOL_OUT:
-               size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case SERVICE_ACTION_IN:
-               switch (cmd->t_task_cdb[1] & 0x1f) {
-               case SAI_READ_CAPACITY_16:
-                       if (!passthrough)
-                               cmd->execute_cmd =
-                                       target_emulate_readcapacity_16;
-                       break;
-               default:
-                       if (passthrough)
-                               break;
-
-                       pr_err("Unsupported SA: 0x%02x\n",
-                               cmd->t_task_cdb[1] & 0x1f);
-                       goto out_invalid_cdb_field;
-               }
-               /*FALLTHROUGH*/
-       case ACCESS_CONTROL_IN:
-       case ACCESS_CONTROL_OUT:
-       case EXTENDED_COPY:
-       case READ_ATTRIBUTE:
-       case RECEIVE_COPY_RESULTS:
-       case WRITE_ATTRIBUTE:
-               size = (cdb[10] << 24) | (cdb[11] << 16) |
-                      (cdb[12] << 8) | cdb[13];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case RECEIVE_DIAGNOSTIC:
-       case SEND_DIAGNOSTIC:
-               size = (cdb[3] << 8) | cdb[4];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */
-#if 0
-       case GPCMD_READ_CD:
-               sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
-               size = (2336 * sectors);
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-#endif
-       case READ_TOC:
-               size = cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case REQUEST_SENSE:
-               size = cdb[4];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_request_sense;
-               break;
-       case READ_ELEMENT_STATUS:
-               size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case WRITE_BUFFER:
-               size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case RESERVE:
-       case RESERVE_10:
-               /*
-                * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
-                * Assume the passthrough or $FABRIC_MOD will tell us about it.
-                */
-               if (cdb[0] == RESERVE_10)
-                       size = (cdb[7] << 8) | cdb[8];
-               else
-                       size = cmd->data_length;
-
-               /*
-                * Setup the legacy emulated handler for SPC-2 and
-                * >= SPC-3 compatible reservation handling (CRH=1)
-                * Otherwise, we assume the underlying SCSI logic is
-                * is running in SPC_PASSTHROUGH, and wants reservations
-                * emulation disabled.
-                */
-               if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
-                       cmd->execute_cmd = target_scsi2_reservation_reserve;
-               cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-               break;
-       case RELEASE:
-       case RELEASE_10:
-               /*
-                * The SPC-2 RELEASE does not contain a size in the SCSI CDB.
-                * Assume the passthrough or $FABRIC_MOD will tell us about it.
-               */
-               if (cdb[0] == RELEASE_10)
-                       size = (cdb[7] << 8) | cdb[8];
-               else
-                       size = cmd->data_length;
-
-               if (su_dev->t10_pr.res_type != SPC_PASSTHROUGH)
-                       cmd->execute_cmd = target_scsi2_reservation_release;
-               cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-               break;
-       case SYNCHRONIZE_CACHE:
-       case SYNCHRONIZE_CACHE_16:
-               /*
-                * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
-                */
-               if (cdb[0] == SYNCHRONIZE_CACHE) {
-                       sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-                       cmd->t_task_lba = transport_lba_32(cdb);
-               } else {
-                       sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-                       cmd->t_task_lba = transport_lba_64(cdb);
-               }
-               if (sector_ret)
-                       goto out_unsupported_cdb;
-
-               size = transport_get_size(sectors, cdb, cmd);
-               cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-
-               if (passthrough)
-                       break;
-
-               /*
-                * Check to ensure that LBA + Range does not exceed past end of
-                * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
-                */
-               if ((cmd->t_task_lba != 0) || (sectors != 0)) {
-                       if (transport_cmd_get_valid_sectors(cmd) < 0)
-                               goto out_invalid_cdb_field;
-               }
-               cmd->execute_cmd = target_emulate_synchronize_cache;
-               break;
-       case UNMAP:
-               size = get_unaligned_be16(&cdb[7]);
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_unmap;
-               break;
-       case WRITE_SAME_16:
-               sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
+       unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
+       struct se_device *dev = cmd->se_dev;
+       unsigned long flags;
+       u32 offset = 0;
 
-               if (sectors)
-                       size = transport_get_size(1, cdb, cmd);
-               else {
-                       pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
-                       goto out_invalid_cdb_field;
-               }
+       WARN_ON(!cmd->se_lun);
 
-               cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+       if (!dev)
+               return 0;
 
-               if (target_check_write_same_discard(&cdb[1], dev) < 0)
-                       goto out_unsupported_cdb;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_write_same;
-               break;
-       case WRITE_SAME:
-               sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
-               if (sector_ret)
-                       goto out_unsupported_cdb;
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               return 0;
+       }
 
-               if (sectors)
-                       size = transport_get_size(1, cdb, cmd);
-               else {
-                       pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
-                       goto out_invalid_cdb_field;
-               }
+       if (!(cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
+               goto out;
 
-               cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               /*
-                * Follow sbcr26 with WRITE_SAME (10) and check for the existence
-                * of byte 1 bit 3 UNMAP instead of original reserved field
-                */
-               if (target_check_write_same_discard(&cdb[1], dev) < 0)
-                       goto out_unsupported_cdb;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_write_same;
-               break;
-       case ALLOW_MEDIUM_REMOVAL:
-       case ERASE:
-       case REZERO_UNIT:
-       case SEEK_10:
-       case SPACE:
-       case START_STOP:
-       case TEST_UNIT_READY:
-       case VERIFY:
-       case WRITE_FILEMARKS:
-               cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-               if (!passthrough)
-                       cmd->execute_cmd = target_emulate_noop;
-               break;
-       case GPCMD_CLOSE_TRACK:
-       case INITIALIZE_ELEMENT_STATUS:
-       case GPCMD_LOAD_UNLOAD:
-       case GPCMD_SET_SPEED:
-       case MOVE_MEDIUM:
-               cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
-               break;
-       case REPORT_LUNS:
-               cmd->execute_cmd = target_report_luns;
-               size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
-               /*
-                * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
-                * See spc4r17 section 5.3
-                */
-               if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
-                       cmd->sam_task_attr = MSG_HEAD_TAG;
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case GET_EVENT_STATUS_NOTIFICATION:
-               size = (cdb[7] << 8) | cdb[8];
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       case ATA_16:
-               /* Only support ATA passthrough to pSCSI backends.. */
-               if (!passthrough)
-                       goto out_unsupported_cdb;
-
-               /* T_LENGTH */
-               switch (cdb[2] & 0x3) {
-               case 0x0:
-                       sectors = 0;
-                       break;
-               case 0x1:
-                       sectors = (((cdb[1] & 0x1) ? cdb[3] : 0) << 8) | cdb[4];
-                       break;
-               case 0x2:
-                       sectors = (((cdb[1] & 0x1) ? cdb[5] : 0) << 8) | cdb[6];
-                       break;
-               case 0x3:
-                       pr_err("T_LENGTH=0x3 not supported for ATA_16\n");
-                       goto out_invalid_cdb_field;
-               }
+       if (!dev->transport->get_sense_buffer) {
+               pr_err("dev->transport->get_sense_buffer is NULL\n");
+               goto out;
+       }
 
-               /* BYTE_BLOCK */
-               if (cdb[2] & 0x4) {
-                       /* BLOCK T_TYPE: 512 or sector */
-                       size = sectors * ((cdb[2] & 0x10) ?
-                               dev->se_sub_dev->se_dev_attrib.block_size : 512);
-               } else {
-                       /* BYTE */
-                       size = sectors;
-               }
-               cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
-               break;
-       default:
-               pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode"
-                       " 0x%02x, sending CHECK_CONDITION.\n",
-                       cmd->se_tfo->get_fabric_name(), cdb[0]);
-               goto out_unsupported_cdb;
+       sense_buffer = dev->transport->get_sense_buffer(cmd);
+       if (!sense_buffer) {
+               pr_err("ITT 0x%08x cmd %p: Unable to locate"
+                       " sense buffer for task with sense\n",
+                       cmd->se_tfo->get_task_tag(cmd), cmd);
+               goto out;
        }
 
-       if (cmd->unknown_data_length)
-               cmd->data_length = size;
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-       if (size != cmd->data_length) {
-               pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
-                       " %u does not match SCSI CDB Length: %u for SAM Opcode:"
-                       " 0x%02x\n", cmd->se_tfo->get_fabric_name(),
-                               cmd->data_length, size, cdb[0]);
+       offset = cmd->se_tfo->set_fabric_sense_len(cmd, TRANSPORT_SENSE_BUFFER);
 
-               cmd->cmd_spdtl = size;
+       memcpy(&buffer[offset], sense_buffer, TRANSPORT_SENSE_BUFFER);
 
-               if (cmd->data_direction == DMA_TO_DEVICE) {
-                       pr_err("Rejecting underflow/overflow"
-                                       " WRITE data\n");
-                       goto out_invalid_cdb_field;
-               }
-               /*
-                * Reject READ_* or WRITE_* with overflow/underflow for
-                * type SCF_SCSI_DATA_SG_IO_CDB.
-                */
-               if (!ret && (dev->se_sub_dev->se_dev_attrib.block_size != 512))  {
-                       pr_err("Failing OVERFLOW/UNDERFLOW for LBA op"
-                               " CDB on non 512-byte sector setup subsystem"
-                               " plugin: %s\n", dev->transport->name);
-                       /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
-                       goto out_invalid_cdb_field;
-               }
+       /* Automatically padded */
+       cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
 
-               if (size > cmd->data_length) {
-                       cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
-                       cmd->residual_count = (size - cmd->data_length);
-               } else {
-                       cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
-                       cmd->residual_count = (cmd->data_length - size);
-               }
-               cmd->data_length = size;
-       }
+       pr_debug("HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x and sense\n",
+               dev->se_hba->hba_id, dev->transport->name, cmd->scsi_status);
+       return 0;
 
-       if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
-               if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) {
-                       printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
-                               " big sectors %u exceeds fabric_max_sectors:"
-                               " %u\n", cdb[0], sectors,
-                               su_dev->se_dev_attrib.fabric_max_sectors);
-                       goto out_invalid_cdb_field;
-               }
-               if (sectors > su_dev->se_dev_attrib.hw_max_sectors) {
-                       printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
-                               " big sectors %u exceeds backend hw_max_sectors:"
-                               " %u\n", cdb[0], sectors,
-                               su_dev->se_dev_attrib.hw_max_sectors);
-                       goto out_invalid_cdb_field;
+out:
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+       return -1;
+}
+
+/*
+ * Process all commands up to the last received ORDERED task attribute which
+ * requires another blocking boundary
+ */
+static void target_restart_delayed_cmds(struct se_device *dev)
+{
+       for (;;) {
+               struct se_cmd *cmd;
+
+               spin_lock(&dev->delayed_cmd_lock);
+               if (list_empty(&dev->delayed_cmd_list)) {
+                       spin_unlock(&dev->delayed_cmd_lock);
+                       break;
                }
-       }
 
-       /* reject any command that we don't have a handler for */
-       if (!(passthrough || cmd->execute_cmd ||
-            (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
-               goto out_unsupported_cdb;
+               cmd = list_entry(dev->delayed_cmd_list.next,
+                                struct se_cmd, se_delayed_node);
+               list_del(&cmd->se_delayed_node);
+               spin_unlock(&dev->delayed_cmd_lock);
 
-       transport_set_supported_SAM_opcode(cmd);
-       return ret;
+               __target_execute_cmd(cmd);
 
-out_unsupported_cdb:
-       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-       cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
-       return -EINVAL;
-out_invalid_cdb_field:
-       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-       cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-       return -EINVAL;
+               if (cmd->sam_task_attr == MSG_ORDERED_TAG)
+                       break;
+       }
 }
 
 /*
@@ -3052,8 +1906,6 @@ out_invalid_cdb_field:
 static void transport_complete_task_attr(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
-       struct se_cmd *cmd_p, *cmd_tmp;
-       int new_active_tasks = 0;
 
        if (cmd->sam_task_attr == MSG_SIMPLE_TAG) {
                atomic_dec(&dev->simple_cmds);
@@ -3075,38 +1927,8 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
                pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:"
                        " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id);
        }
-       /*
-        * Process all commands up to the last received
-        * ORDERED task attribute which requires another blocking
-        * boundary
-        */
-       spin_lock(&dev->delayed_cmd_lock);
-       list_for_each_entry_safe(cmd_p, cmd_tmp,
-                       &dev->delayed_cmd_list, se_delayed_node) {
 
-               list_del(&cmd_p->se_delayed_node);
-               spin_unlock(&dev->delayed_cmd_lock);
-
-               pr_debug("Calling add_tasks() for"
-                       " cmd_p: 0x%02x Task Attr: 0x%02x"
-                       " Dormant -> Active, se_ordered_id: %u\n",
-                       cmd_p->t_task_cdb[0],
-                       cmd_p->sam_task_attr, cmd_p->se_ordered_id);
-
-               target_add_to_execute_list(cmd_p);
-               new_active_tasks++;
-
-               spin_lock(&dev->delayed_cmd_lock);
-               if (cmd_p->sam_task_attr == MSG_ORDERED_TAG)
-                       break;
-       }
-       spin_unlock(&dev->delayed_cmd_lock);
-       /*
-        * If new tasks have become active, wake up the transport thread
-        * to do the processing of the Active tasks.
-        */
-       if (new_active_tasks != 0)
-               wake_up_interruptible(&dev->dev_queue_obj.thread_wq);
+       target_restart_delayed_cmds(dev);
 }
 
 static void transport_complete_qf(struct se_cmd *cmd)
@@ -3365,31 +2187,27 @@ int transport_generic_map_mem_to_cmd(
        if (!sgl || !sgl_count)
                return 0;
 
-       if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
-           (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
-               /*
-                * Reject SCSI data overflow with map_mem_to_cmd() as incoming
-                * scatterlists already have been set to follow what the fabric
-                * passes for the original expected data transfer length.
-                */
-               if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
-                       pr_warn("Rejecting SCSI DATA overflow for fabric using"
-                               " SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n");
-                       cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
-                       cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
-                       return -EINVAL;
-               }
+       /*
+        * Reject SCSI data overflow with map_mem_to_cmd() as incoming
+        * scatterlists already have been set to follow what the fabric
+        * passes for the original expected data transfer length.
+        */
+       if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+               pr_warn("Rejecting SCSI DATA overflow for fabric using"
+                       " SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n");
+               cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+               cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+               return -EINVAL;
+       }
 
-               cmd->t_data_sg = sgl;
-               cmd->t_data_nents = sgl_count;
+       cmd->t_data_sg = sgl;
+       cmd->t_data_nents = sgl_count;
 
-               if (sgl_bidi && sgl_bidi_count) {
-                       cmd->t_bidi_data_sg = sgl_bidi;
-                       cmd->t_bidi_data_nents = sgl_bidi_count;
-               }
-               cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+       if (sgl_bidi && sgl_bidi_count) {
+               cmd->t_bidi_data_sg = sgl_bidi;
+               cmd->t_bidi_data_nents = sgl_bidi_count;
        }
-
+       cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
        return 0;
 }
 EXPORT_SYMBOL(transport_generic_map_mem_to_cmd);
@@ -3461,7 +2279,7 @@ transport_generic_get_mem(struct se_cmd *cmd)
        cmd->t_data_nents = nents;
        sg_init_table(cmd->t_data_sg, nents);
 
-       zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB ? 0 : __GFP_ZERO;
+       zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_CDB ? 0 : __GFP_ZERO;
 
        while (length) {
                u32 page_len = min_t(u32, length, PAGE_SIZE);
@@ -3492,7 +2310,6 @@ out:
  */
 int transport_generic_new_cmd(struct se_cmd *cmd)
 {
-       struct se_device *dev = cmd->se_dev;
        int ret = 0;
 
        /*
@@ -3508,8 +2325,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
        }
 
        /* Workaround for handling zero-length control CDBs */
-       if ((cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) &&
-           !cmd->data_length) {
+       if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) && !cmd->data_length) {
                spin_lock_irq(&cmd->t_state_lock);
                cmd->t_state = TRANSPORT_COMPLETE;
                cmd->transport_state |= CMD_T_ACTIVE;
@@ -3527,52 +2343,45 @@ int transport_generic_new_cmd(struct se_cmd *cmd)
                return 0;
        }
 
-       if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
-               struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib;
-
-               if (transport_cmd_get_valid_sectors(cmd) < 0)
-                       return -EINVAL;
-
-               BUG_ON(cmd->data_length % attr->block_size);
-               BUG_ON(DIV_ROUND_UP(cmd->data_length, attr->block_size) >
-                       attr->hw_max_sectors);
-       }
-
        atomic_inc(&cmd->t_fe_count);
 
        /*
-        * For WRITEs, let the fabric know its buffer is ready.
-        *
-        * The command will be added to the execution queue after its write
-        * data has arrived.
+        * If this command is not a write we can execute it right here,
+        * for write buffers we need to notify the fabric driver first
+        * and let it call back once the write buffers are ready.
         */
-       if (cmd->data_direction == DMA_TO_DEVICE) {
-               target_add_to_state_list(cmd);
-               return transport_generic_write_pending(cmd);
+       target_add_to_state_list(cmd);
+       if (cmd->data_direction != DMA_TO_DEVICE) {
+               target_execute_cmd(cmd);
+               return 0;
        }
-       /*
-        * Everything else but a WRITE, add the command to the execution queue.
-        */
-       transport_execute_tasks(cmd);
-       return 0;
+
+       spin_lock_irq(&cmd->t_state_lock);
+       cmd->t_state = TRANSPORT_WRITE_PENDING;
+       spin_unlock_irq(&cmd->t_state_lock);
+
+       transport_cmd_check_stop(cmd, false);
+
+       ret = cmd->se_tfo->write_pending(cmd);
+       if (ret == -EAGAIN || ret == -ENOMEM)
+               goto queue_full;
+
+       if (ret < 0)
+               return ret;
+       return 1;
 
 out_fail:
        cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
        cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        return -EINVAL;
+queue_full:
+       pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd);
+       cmd->t_state = TRANSPORT_COMPLETE_QF_WP;
+       transport_handle_queue_full(cmd, cmd->se_dev);
+       return 0;
 }
 EXPORT_SYMBOL(transport_generic_new_cmd);
 
-/*     transport_generic_process_write():
- *
- *
- */
-void transport_generic_process_write(struct se_cmd *cmd)
-{
-       transport_execute_tasks(cmd);
-}
-EXPORT_SYMBOL(transport_generic_process_write);
-
 static void transport_write_pending_qf(struct se_cmd *cmd)
 {
        int ret;
@@ -3585,43 +2394,6 @@ static void transport_write_pending_qf(struct se_cmd *cmd)
        }
 }
 
-static int transport_generic_write_pending(struct se_cmd *cmd)
-{
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
-       cmd->t_state = TRANSPORT_WRITE_PENDING;
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-
-       /*
-        * Clear the se_cmd for WRITE_PENDING status in order to set
-        * CMD_T_ACTIVE so that transport_generic_handle_data can be called
-        * from HW target mode interrupt code.  This is safe to be called
-        * with transport_off=1 before the cmd->se_tfo->write_pending
-        * because the se_cmd->se_lun pointer is not being cleared.
-        */
-       transport_cmd_check_stop(cmd, 1, 0);
-
-       /*
-        * Call the fabric write_pending function here to let the
-        * frontend know that WRITE buffers are ready.
-        */
-       ret = cmd->se_tfo->write_pending(cmd);
-       if (ret == -EAGAIN || ret == -ENOMEM)
-               goto queue_full;
-       else if (ret < 0)
-               return ret;
-
-       return 1;
-
-queue_full:
-       pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd);
-       cmd->t_state = TRANSPORT_COMPLETE_QF_WP;
-       transport_handle_queue_full(cmd, cmd->se_dev);
-       return 0;
-}
-
 void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
 {
        if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
@@ -3648,10 +2420,11 @@ EXPORT_SYMBOL(transport_generic_free_cmd);
  * @se_cmd:    command descriptor to add
  * @ack_kref:  Signal that fabric will perform an ack target_put_sess_cmd()
  */
-void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
-                       bool ack_kref)
+static int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
+                              bool ack_kref)
 {
        unsigned long flags;
+       int ret = 0;
 
        kref_init(&se_cmd->cmd_kref);
        /*
@@ -3665,11 +2438,17 @@ void target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
        }
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+       if (se_sess->sess_tearing_down) {
+               ret = -ESHUTDOWN;
+               goto out;
+       }
        list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
        se_cmd->check_release = 1;
+
+out:
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+       return ret;
 }
-EXPORT_SYMBOL(target_get_sess_cmd);
 
 static void target_release_cmd_kref(struct kref *kref)
 {
@@ -3704,28 +2483,27 @@ int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
 }
 EXPORT_SYMBOL(target_put_sess_cmd);
 
-/* target_splice_sess_cmd_list - Split active cmds into sess_wait_list
- * @se_sess:   session to split
+/* target_sess_cmd_list_set_waiting - Flag all commands in
+ *         sess_cmd_list to complete cmd_wait_comp.  Set
+ *         sess_tearing_down so no more commands are queued.
+ * @se_sess:   session to flag
  */
-void target_splice_sess_cmd_list(struct se_session *se_sess)
+void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
 {
        struct se_cmd *se_cmd;
        unsigned long flags;
 
-       WARN_ON(!list_empty(&se_sess->sess_wait_list));
-       INIT_LIST_HEAD(&se_sess->sess_wait_list);
-
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-       se_sess->sess_tearing_down = 1;
 
-       list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
+       WARN_ON(se_sess->sess_tearing_down);
+       se_sess->sess_tearing_down = 1;
 
-       list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
+       list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list)
                se_cmd->cmd_wait_set = 1;
 
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 }
-EXPORT_SYMBOL(target_splice_sess_cmd_list);
+EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
 
 /* target_wait_for_sess_cmds - Wait for outstanding descriptors
  * @se_sess:    session to wait for active I/O
@@ -3739,7 +2517,7 @@ void target_wait_for_sess_cmds(
        bool rc = false;
 
        list_for_each_entry_safe(se_cmd, tmp_cmd,
-                               &se_sess->sess_wait_list, se_cmd_list) {
+                               &se_sess->sess_cmd_list, se_cmd_list) {
                list_del(&se_cmd->se_cmd_list);
 
                pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
@@ -3791,26 +2569,20 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
                pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n",
                         cmd->se_tfo->get_task_tag(cmd));
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-               transport_cmd_check_stop(cmd, 1, 0);
+               transport_cmd_check_stop(cmd, false);
                return -EPERM;
        }
        cmd->transport_state |= CMD_T_LUN_FE_STOP;
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-       wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq);
-
        // XXX: audit task_flags checks.
        spin_lock_irqsave(&cmd->t_state_lock, flags);
        if ((cmd->transport_state & CMD_T_BUSY) &&
            (cmd->transport_state & CMD_T_SENT)) {
                if (!target_stop_cmd(cmd, &flags))
                        ret++;
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-       } else {
-               spin_unlock_irqrestore(&cmd->t_state_lock,
-                               flags);
-               target_remove_from_execute_list(cmd);
        }
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
        pr_debug("ConfigFS: cmd: %p stop tasks ret:"
                        " %d\n", cmd, ret);
@@ -3821,7 +2593,6 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
                pr_debug("ConfigFS: ITT[0x%08x] - stopped cmd....\n",
                                cmd->se_tfo->get_task_tag(cmd));
        }
-       transport_remove_cmd_from_queue(cmd);
 
        return 0;
 }
@@ -3840,11 +2611,6 @@ static void __transport_clear_lun_from_sessions(struct se_lun *lun)
                       struct se_cmd, se_lun_node);
                list_del_init(&cmd->se_lun_node);
 
-               /*
-                * This will notify iscsi_target_transport.c:
-                * transport_cmd_check_stop() that a LUN shutdown is in
-                * progress for the iscsi_cmd_t.
-                */
                spin_lock(&cmd->t_state_lock);
                pr_debug("SE_LUN[%d] - Setting cmd->transport"
                        "_lun_stop for  ITT: 0x%08x\n",
@@ -3911,7 +2677,7 @@ check_cond:
 
                        spin_unlock_irqrestore(&cmd->t_state_lock,
                                        cmd_flags);
-                       transport_cmd_check_stop(cmd, 1, 0);
+                       transport_cmd_check_stop(cmd, false);
                        complete(&cmd->transport_lun_fe_stop_comp);
                        spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
                        continue;
@@ -3967,10 +2733,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
                return false;
        }
-       /*
-        * Only perform a possible wait_for_tasks if SCF_SUPPORTED_SAM_OPCODE
-        * has been set in transport_set_supported_SAM_opcode().
-        */
+
        if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) &&
            !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
@@ -4028,8 +2791,6 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
 
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-       wake_up_interruptible(&cmd->se_dev->dev_queue_obj.thread_wq);
-
        wait_for_completion(&cmd->t_transport_stop_comp);
 
        spin_lock_irqsave(&cmd->t_state_lock, flags);
@@ -4212,6 +2973,15 @@ int transport_send_check_condition_and_sense(
                /* WRITE PROTECTED */
                buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27;
                break;
+       case TCM_ADDRESS_OUT_OF_RANGE:
+               /* CURRENT ERROR */
+               buffer[offset] = 0x70;
+               buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* LOGICAL BLOCK ADDRESS OUT OF RANGE */
+               buffer[offset+SPC_ASC_KEY_OFFSET] = 0x21;
+               break;
        case TCM_CHECK_CONDITION_UNIT_ATTENTION:
                /* CURRENT ERROR */
                buffer[offset] = 0x70;
@@ -4312,8 +3082,9 @@ void transport_send_task_abort(struct se_cmd *cmd)
        cmd->se_tfo->queue_status(cmd);
 }
 
-static int transport_generic_do_tmr(struct se_cmd *cmd)
+static void target_tmr_work(struct work_struct *work)
 {
+       struct se_cmd *cmd = container_of(work, struct se_cmd, work);
        struct se_device *dev = cmd->se_dev;
        struct se_tmr_req *tmr = cmd->se_tmr_req;
        int ret;
@@ -4349,80 +3120,13 @@ static int transport_generic_do_tmr(struct se_cmd *cmd)
        cmd->se_tfo->queue_tm_rsp(cmd);
 
        transport_cmd_check_stop_to_fabric(cmd);
-       return 0;
 }
 
-/*     transport_processing_thread():
- *
- *
- */
-static int transport_processing_thread(void *param)
+int transport_generic_handle_tmr(
+       struct se_cmd *cmd)
 {
-       int ret;
-       struct se_cmd *cmd;
-       struct se_device *dev = param;
-
-       while (!kthread_should_stop()) {
-               ret = wait_event_interruptible(dev->dev_queue_obj.thread_wq,
-                               atomic_read(&dev->dev_queue_obj.queue_cnt) ||
-                               kthread_should_stop());
-               if (ret < 0)
-                       goto out;
-
-get_cmd:
-               cmd = transport_get_cmd_from_queue(&dev->dev_queue_obj);
-               if (!cmd)
-                       continue;
-
-               switch (cmd->t_state) {
-               case TRANSPORT_NEW_CMD:
-                       BUG();
-                       break;
-               case TRANSPORT_NEW_CMD_MAP:
-                       if (!cmd->se_tfo->new_cmd_map) {
-                               pr_err("cmd->se_tfo->new_cmd_map is"
-                                       " NULL for TRANSPORT_NEW_CMD_MAP\n");
-                               BUG();
-                       }
-                       ret = cmd->se_tfo->new_cmd_map(cmd);
-                       if (ret < 0) {
-                               transport_generic_request_failure(cmd);
-                               break;
-                       }
-                       ret = transport_generic_new_cmd(cmd);
-                       if (ret < 0) {
-                               transport_generic_request_failure(cmd);
-                               break;
-                       }
-                       break;
-               case TRANSPORT_PROCESS_WRITE:
-                       transport_generic_process_write(cmd);
-                       break;
-               case TRANSPORT_PROCESS_TMR:
-                       transport_generic_do_tmr(cmd);
-                       break;
-               case TRANSPORT_COMPLETE_QF_WP:
-                       transport_write_pending_qf(cmd);
-                       break;
-               case TRANSPORT_COMPLETE_QF_OK:
-                       transport_complete_qf(cmd);
-                       break;
-               default:
-                       pr_err("Unknown t_state: %d  for ITT: 0x%08x "
-                               "i_state: %d on SE LUN: %u\n",
-                               cmd->t_state,
-                               cmd->se_tfo->get_task_tag(cmd),
-                               cmd->se_tfo->get_cmd_state(cmd),
-                               cmd->se_lun->unpacked_lun);
-                       BUG();
-               }
-
-               goto get_cmd;
-       }
-
-out:
-       WARN_ON(!list_empty(&dev->state_list));
-       WARN_ON(!list_empty(&dev->dev_queue_obj.qobj_list));
-       dev->process_thread = NULL;
+       INIT_WORK(&cmd->work, target_tmr_work);
+       queue_work(cmd->se_dev->tmr_wq, &cmd->work);
        return 0;
 }
+EXPORT_SYMBOL(transport_generic_handle_tmr);
index f03fb9730f5bb89a0cd003817544693e3600e383..b9cb5006177e22166732032468bf8d0a733299f8 100644 (file)
@@ -215,7 +215,7 @@ int ft_write_pending(struct se_cmd *se_cmd)
                 */
                if ((ep->xid <= lport->lro_xid) &&
                    (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
-                       if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) &&
+                       if ((se_cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) &&
                            lport->tt.ddp_target(lport, ep->xid,
                                                 se_cmd->t_data_sg,
                                                 se_cmd->t_data_nents))
@@ -230,6 +230,8 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd)
 {
        struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);
 
+       if (cmd->aborted)
+               return ~0;
        return fc_seq_exch(cmd->seq)->rxid;
 }
 
@@ -541,9 +543,11 @@ static void ft_send_work(struct work_struct *work)
         * Use a single se_cmd->cmd_kref as we expect to release se_cmd
         * directly from ft_check_stop_free callback in response path.
         */
-       target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
-                       &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
-                       ntohl(fcp->fc_dl), task_attr, data_dir, 0);
+       if (target_submit_cmd(&cmd->se_cmd, cmd->sess->se_sess, fcp->fc_cdb,
+                             &cmd->ft_sense_buffer[0], scsilun_to_int(&fcp->fc_lun),
+                             ntohl(fcp->fc_dl), task_attr, data_dir, 0))
+               goto err;
+
        pr_debug("r_ctl %x alloc target_submit_cmd\n", fh->fh_r_ctl);
        return;
 
index 071a505f98fc13256fa536f4a39cae111ccd1050..ad36ede1a1eab12b907964ca8c446262d2918528 100644 (file)
@@ -183,6 +183,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
        return ft_queue_status(se_cmd);
 }
 
+static void ft_execute_work(struct work_struct *work)
+{
+       struct ft_cmd *cmd = container_of(work, struct ft_cmd, work);
+
+       target_execute_cmd(&cmd->se_cmd);
+}
+
 /*
  * Receive write data frame.
  */
@@ -307,8 +314,10 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp)
                cmd->write_data_len += tlen;
        }
 last_frame:
-       if (cmd->write_data_len == se_cmd->data_length)
-               transport_generic_handle_data(se_cmd);
+       if (cmd->write_data_len == se_cmd->data_length) {
+               INIT_WORK(&cmd->work, ft_execute_work);
+               queue_work(cmd->sess->tport->tpg->workqueue, &cmd->work);
+       }
 drop:
        fc_frame_free(fp);
 }
index cb99da920068986d2c2153f6af507781561074d5..87901fa74dd7e1acb136cbdf0607aa4b8eeeb652 100644 (file)
@@ -58,7 +58,8 @@ static struct ft_tport *ft_tport_create(struct fc_lport *lport)
        struct ft_tport *tport;
        int i;
 
-       tport = rcu_dereference(lport->prov[FC_TYPE_FCP]);
+       tport = rcu_dereference_protected(lport->prov[FC_TYPE_FCP],
+                                         lockdep_is_held(&ft_lport_lock));
        if (tport && tport->tpg)
                return tport;
 
index ced26c8ccd573eb8e6757a30681901b7a0ac88eb..0d2ea0c224c35c6012e0d6c1f7fe04ff337a8931 100644 (file)
@@ -401,7 +401,7 @@ out:
 }
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL_RAW
-void __init udbg_init_debug_opal(void)
+void __init udbg_init_debug_opal_raw(void)
 {
        u32 index = CONFIG_PPC_EARLY_DEBUG_OPAL_VTERMNO;
        hvc_opal_privs[index] = &hvc_opal_boot_priv;
index ec56d8397aae4f2caca41058574ec2b3fcd36356..2e341b81ff891b632e5cbee6d2337aba0f10cfe8 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/of_device.h>
 
 #include <asm/cacheflush.h>
 
@@ -675,6 +676,30 @@ static struct uart_driver auart_driver = {
 #endif
 };
 
+/*
+ * This function returns 1 if pdev isn't a device instatiated by dt, 0 if it
+ * could successfully get all information from dt or a negative errno.
+ */
+static int serial_mxs_probe_dt(struct mxs_auart_port *s,
+               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       if (!np)
+               /* no device tree device */
+               return 1;
+
+       ret = of_alias_get_id(np, "serial");
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
+               return ret;
+       }
+       s->port.line = ret;
+
+       return 0;
+}
+
 static int __devinit mxs_auart_probe(struct platform_device *pdev)
 {
        struct mxs_auart_port *s;
@@ -689,6 +714,12 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
                goto out;
        }
 
+       ret = serial_mxs_probe_dt(s, pdev);
+       if (ret > 0)
+               s->port.line = pdev->id < 0 ? 0 : pdev->id;
+       else if (ret < 0)
+               goto out_free;
+
        pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
        if (IS_ERR(pinctrl)) {
                ret = PTR_ERR(pinctrl);
@@ -711,7 +742,6 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
        s->port.membase = ioremap(r->start, resource_size(r));
        s->port.ops = &mxs_auart_ops;
        s->port.iotype = UPIO_MEM;
-       s->port.line = pdev->id < 0 ? 0 : pdev->id;
        s->port.fifosize = 16;
        s->port.uartclk = clk_get_rate(s->clk);
        s->port.type = PORT_IMX;
@@ -728,7 +758,7 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, s);
 
-       auart_port[pdev->id] = s;
+       auart_port[s->port.line] = s;
 
        mxs_auart_reset(&s->port);
 
@@ -769,12 +799,19 @@ static int __devexit mxs_auart_remove(struct platform_device *pdev)
        return 0;
 }
 
+static struct of_device_id mxs_auart_dt_ids[] = {
+       { .compatible = "fsl,imx23-auart", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_auart_dt_ids);
+
 static struct platform_driver mxs_auart_driver = {
        .probe = mxs_auart_probe,
        .remove = __devexit_p(mxs_auart_remove),
        .driver = {
                .name = "mxs-auart",
                .owner = THIS_MODULE,
+               .of_match_table = mxs_auart_dt_ids,
        },
 };
 
@@ -807,3 +844,4 @@ module_init(mxs_auart_init);
 module_exit(mxs_auart_exit);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Freescale MXS application uart driver");
+MODULE_ALIAS("platform:mxs-auart");
index 8fd398dffced7fe90afb5a6b13464279f3a7c5c6..ee469274a3fe0d03aed9259f5f4c380330742aa3 100644 (file)
@@ -500,6 +500,8 @@ retry:
                        goto retry;
                }
                if (!desc->reslength) { /* zero length read */
+                       dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
+                       clear_bit(WDM_READ, &desc->flags);
                        spin_unlock_irq(&desc->iuspin);
                        goto retry;
                }
index 25a7422ee657b91021b6858615666b00a9ab19a2..8fb484984c86c6f6532d4ac8696cd5f6f4a7e5ff 100644 (file)
@@ -2324,12 +2324,16 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
 static int hub_port_reset(struct usb_hub *hub, int port1,
                        struct usb_device *udev, unsigned int delay, bool warm);
 
-/* Is a USB 3.0 port in the Inactive state? */
-static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus)
+/* Is a USB 3.0 port in the Inactive or Complinance Mode state?
+ * Port worm reset is required to recover
+ */
+static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus)
 {
        return hub_is_superspeed(hub->hdev) &&
-               (portstatus & USB_PORT_STAT_LINK_STATE) ==
-               USB_SS_PORT_LS_SS_INACTIVE;
+               (((portstatus & USB_PORT_STAT_LINK_STATE) ==
+                 USB_SS_PORT_LS_SS_INACTIVE) ||
+                ((portstatus & USB_PORT_STAT_LINK_STATE) ==
+                 USB_SS_PORT_LS_COMP_MOD)) ;
 }
 
 static int hub_port_wait_reset(struct usb_hub *hub, int port1,
@@ -2365,7 +2369,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                         *
                         * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
                         */
-                       if (hub_port_inactive(hub, portstatus)) {
+                       if (hub_port_warm_reset_required(hub, portstatus)) {
                                int ret;
 
                                if ((portchange & USB_PORT_STAT_C_CONNECTION))
@@ -4408,9 +4412,7 @@ static void hub_events(void)
                        /* Warm reset a USB3 protocol port if it's in
                         * SS.Inactive state.
                         */
-                       if (hub_is_superspeed(hub->hdev) &&
-                               (portstatus & USB_PORT_STAT_LINK_STATE)
-                                       == USB_SS_PORT_LS_SS_INACTIVE) {
+                       if (hub_port_warm_reset_required(hub, portstatus)) {
                                dev_dbg(hub_dev, "warm reset port %d\n", i);
                                hub_port_reset(hub, i, NULL,
                                                HUB_BH_RESET_TIME, true);
index c46439c8dd7462b2ba39e38f7129a9a1fa10ab41..5444866e13ef72c8ddd7c9a693803c02cd37a61a 100644 (file)
@@ -294,7 +294,7 @@ static int bot_send_write_request(struct usbg_cmd *cmd)
                pr_err("%s(%d)\n", __func__, __LINE__);
 
        wait_for_completion(&cmd->write_complete);
-       transport_generic_process_write(se_cmd);
+       target_execute_cmd(se_cmd);
 cleanup:
        return ret;
 }
@@ -725,7 +725,7 @@ static int uasp_send_write_request(struct usbg_cmd *cmd)
        }
 
        wait_for_completion(&cmd->write_complete);
-       transport_generic_process_write(se_cmd);
+       target_execute_cmd(se_cmd);
 cleanup:
        return ret;
 }
@@ -1065,16 +1065,20 @@ static void usbg_cmd_work(struct work_struct *work)
                                tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
                                tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
                                cmd->prio_attr, cmd->sense_iu.sense);
-
-               transport_send_check_condition_and_sense(se_cmd,
-                               TCM_UNSUPPORTED_SCSI_OPCODE, 1);
-               usbg_cleanup_cmd(cmd);
-               return;
+               goto out;
        }
 
-       target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+       if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
                        cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
-                       0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
+                       0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0)
+               goto out;
+
+       return;
+
+out:
+       transport_send_check_condition_and_sense(se_cmd,
+                       TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+       usbg_cleanup_cmd(cmd);
 }
 
 static int usbg_submit_command(struct f_uas *fu,
@@ -1177,16 +1181,20 @@ static void bot_cmd_work(struct work_struct *work)
                                tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
                                tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
                                cmd->prio_attr, cmd->sense_iu.sense);
-
-               transport_send_check_condition_and_sense(se_cmd,
-                               TCM_UNSUPPORTED_SCSI_OPCODE, 1);
-               usbg_cleanup_cmd(cmd);
-               return;
+               goto out;
        }
 
-       target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+       if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
                        cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
-                       cmd->data_len, cmd->prio_attr, dir, 0);
+                       cmd->data_len, cmd->prio_attr, dir, 0) < 0)
+               goto out;
+
+       return;
+
+out:
+       transport_send_check_condition_and_sense(se_cmd,
+                               TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+       usbg_cleanup_cmd(cmd);
 }
 
 static int bot_submit_command(struct f_uas *fu,
@@ -1400,19 +1408,6 @@ static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
        return 1;
 }
 
-static int usbg_new_cmd(struct se_cmd *se_cmd)
-{
-       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-                       se_cmd);
-       int ret;
-
-       ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
-       if (ret)
-               return ret;
-
-       return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
-}
-
 static void usbg_cmd_release(struct kref *ref)
 {
        struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
@@ -1902,7 +1897,6 @@ static struct target_core_fabric_ops usbg_ops = {
        .tpg_alloc_fabric_acl           = usbg_alloc_fabric_acl,
        .tpg_release_fabric_acl         = usbg_release_fabric_acl,
        .tpg_get_inst_index             = usbg_tpg_get_inst_index,
-       .new_cmd_map                    = usbg_new_cmd,
        .release_cmd                    = usbg_release_cmd,
        .shutdown_session               = usbg_shutdown_session,
        .close_session                  = usbg_close_session,
index 17cfb8a1131c254b411364d86a527d24677d15c1..c30435499a029de5ea40c24bfe6148feeadbebf5 100644 (file)
@@ -281,14 +281,13 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
                }
        }
 
+       /* Hold PHYs in reset while initializing EHCI controller */
        if (pdata->phy_reset) {
                if (gpio_is_valid(pdata->reset_gpio_port[0]))
-                       gpio_request_one(pdata->reset_gpio_port[0],
-                                        GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+                       gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
 
                if (gpio_is_valid(pdata->reset_gpio_port[1]))
-                       gpio_request_one(pdata->reset_gpio_port[1],
-                                        GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+                       gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
 
                /* Hold the PHY in RESET for enough time till DIR is high */
                udelay(10);
@@ -330,6 +329,11 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
        omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
 
        ehci_reset(omap_ehci);
+       ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (ret) {
+               dev_err(dev, "failed to add hcd with err %d\n", ret);
+               goto err_add_hcd;
+       }
 
        if (pdata->phy_reset) {
                /* Hold the PHY in RESET for enough time till
@@ -344,12 +348,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
                        gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
        }
 
-       ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
-       if (ret) {
-               dev_err(dev, "failed to add hcd with err %d\n", ret);
-               goto err_add_hcd;
-       }
-
        /* root ports should always stay powered */
        ehci_port_power(omap_ehci, 1);
 
index 2732ef660c5c08b85baeb38c23d5ec597bf15673..7b01094d7993957dba556c4231b781a524ad72e9 100644 (file)
@@ -462,6 +462,42 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
        }
 }
 
+/* Updates Link Status for super Speed port */
+static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
+{
+       u32 pls = status_reg & PORT_PLS_MASK;
+
+       /* resume state is a xHCI internal state.
+        * Do not report it to usb core.
+        */
+       if (pls == XDEV_RESUME)
+               return;
+
+       /* When the CAS bit is set then warm reset
+        * should be performed on port
+        */
+       if (status_reg & PORT_CAS) {
+               /* The CAS bit can be set while the port is
+                * in any link state.
+                * Only roothubs have CAS bit, so we
+                * pretend to be in compliance mode
+                * unless we're already in compliance
+                * or the inactive state.
+                */
+               if (pls != USB_SS_PORT_LS_COMP_MOD &&
+                   pls != USB_SS_PORT_LS_SS_INACTIVE) {
+                       pls = USB_SS_PORT_LS_COMP_MOD;
+               }
+               /* Return also connection bit -
+                * hub state machine resets port
+                * when this bit is set.
+                */
+               pls |= USB_PORT_STAT_CONNECTION;
+       }
+       /* update status field */
+       *status |= pls;
+}
+
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                u16 wIndex, char *buf, u16 wLength)
 {
@@ -606,13 +642,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        else
                                status |= USB_PORT_STAT_POWER;
                }
-               /* Port Link State */
+               /* Update Port Link State for super speed ports*/
                if (hcd->speed == HCD_USB3) {
-                       /* resume state is a xHCI internal state.
-                        * Do not report it to usb core.
-                        */
-                       if ((temp & PORT_PLS_MASK) != XDEV_RESUME)
-                               status |= (temp & PORT_PLS_MASK);
+                       xhci_hub_report_link_state(&status, temp);
                }
                if (bus_state->port_c_suspend & (1 << wIndex))
                        status |= 1 << USB_PORT_FEAT_C_SUSPEND;
index 23b4aefd103609bcf91b8341a6758a9fc4c3b618..8275645889da4ce779c08c88ac4ea06473f222e0 100644 (file)
@@ -885,6 +885,17 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
        num_trbs_free_temp = ep_ring->num_trbs_free;
        dequeue_temp = ep_ring->dequeue;
 
+       /* If we get two back-to-back stalls, and the first stalled transfer
+        * ends just before a link TRB, the dequeue pointer will be left on
+        * the link TRB by the code in the while loop.  So we have to update
+        * the dequeue pointer one segment further, or we'll jump off
+        * the segment into la-la-land.
+        */
+       if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) {
+               ep_ring->deq_seg = ep_ring->deq_seg->next;
+               ep_ring->dequeue = ep_ring->deq_seg->trbs;
+       }
+
        while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
                /* We have more usable TRBs */
                ep_ring->num_trbs_free++;
index de3d6e3e57be4b12e840f5a168b439b151fe84fc..55c0785810c99fb5286e29d39cd4d7ff2b98addb 100644 (file)
@@ -341,7 +341,11 @@ struct xhci_op_regs {
 #define PORT_PLC       (1 << 22)
 /* port configure error change - port failed to configure its link partner */
 #define PORT_CEC       (1 << 23)
-/* bit 24 reserved */
+/* Cold Attach Status - xHC can set this bit to report device attached during
+ * Sx state. Warm port reset should be perfomed to clear this bit and move port
+ * to connected state.
+ */
+#define PORT_CAS       (1 << 24)
 /* wake on connect (enable) */
 #define PORT_WKCONN_E  (1 << 25)
 /* wake on disconnect (enable) */
index 81423f7361dbe8f770086c3a03f6aca09b4beb2c..d47eb06fe463b51463cb899659a5f2428d5bd24b 100644 (file)
@@ -222,14 +222,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
        metro_priv->throttled = 0;
        spin_unlock_irqrestore(&metro_priv->lock, flags);
 
-       /*
-        * Force low_latency on so that our tty_push actually forces the data
-        * through, otherwise it is scheduled, and with high data rates (like
-        * with OHCI) data can get lost.
-        */
-       if (tty)
-               tty->low_latency = 1;
-
        /* Clear the urb pipe. */
        usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);
 
index adf8ce72be50fb9fed94377fc54a7e22814a832f..417ab1b0aa30fe4088daf4017b5035b325bb0f3a 100644 (file)
@@ -497,6 +497,15 @@ static void option_instat_callback(struct urb *urb);
 
 /* MediaTek products */
 #define MEDIATEK_VENDOR_ID                     0x0e8d
+#define MEDIATEK_PRODUCT_DC_1COM               0x00a0
+#define MEDIATEK_PRODUCT_DC_4COM               0x00a5
+#define MEDIATEK_PRODUCT_DC_5COM               0x00a4
+#define MEDIATEK_PRODUCT_7208_1COM             0x7101
+#define MEDIATEK_PRODUCT_7208_2COM             0x7102
+#define MEDIATEK_PRODUCT_FP_1COM               0x0003
+#define MEDIATEK_PRODUCT_FP_2COM               0x0023
+#define MEDIATEK_PRODUCT_FPDC_1COM             0x0043
+#define MEDIATEK_PRODUCT_FPDC_2COM             0x0033
 
 /* Cellient products */
 #define CELLIENT_VENDOR_ID                     0x2692
@@ -554,6 +563,10 @@ static const struct option_blacklist_info net_intf1_blacklist = {
        .reserved = BIT(1),
 };
 
+static const struct option_blacklist_info net_intf2_blacklist = {
+       .reserved = BIT(2),
+};
+
 static const struct option_blacklist_info net_intf3_blacklist = {
        .reserved = BIT(3),
 };
@@ -1099,6 +1112,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff),
+               .driver_info = (kernel_ulong_t)&net_intf2_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,
          0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) },
@@ -1240,6 +1255,17 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) },        /* MediaTek MT6276M modem & app port */
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) },
        { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
        { } /* Terminating entry */
 };
index abbe691047bde3ac8cdc05042a27873be649ea71..49619b4415000efc1ef87756d09667017a682244 100644 (file)
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/pinctrl/consumer.h>
-#include <mach/mxsfb.h>
+#include <linux/mxsfb.h>
 
 #define REG_SET        4
 #define REG_CLR        8
@@ -750,16 +752,43 @@ static void __devexit mxsfb_free_videomem(struct mxsfb_info *host)
        }
 }
 
+static struct platform_device_id mxsfb_devtype[] = {
+       {
+               .name = "imx23-fb",
+               .driver_data = MXSFB_V3,
+       }, {
+               .name = "imx28-fb",
+               .driver_data = MXSFB_V4,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
+
+static const struct of_device_id mxsfb_dt_ids[] = {
+       { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
+       { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
+
 static int __devinit mxsfb_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *of_id =
+                       of_match_device(mxsfb_dt_ids, &pdev->dev);
        struct mxsfb_platform_data *pdata = pdev->dev.platform_data;
        struct resource *res;
        struct mxsfb_info *host;
        struct fb_info *fb_info;
        struct fb_modelist *modelist;
        struct pinctrl *pinctrl;
+       int panel_enable;
+       enum of_gpio_flags flags;
        int i, ret;
 
+       if (of_id)
+               pdev->id_entry = of_id->data;
+
        if (!pdata) {
                dev_err(&pdev->dev, "No platformdata. Giving up\n");
                return -ENODEV;
@@ -807,6 +836,22 @@ static int __devinit mxsfb_probe(struct platform_device *pdev)
                goto error_getclock;
        }
 
+       panel_enable = of_get_named_gpio_flags(pdev->dev.of_node,
+                                              "panel-enable-gpios", 0, &flags);
+       if (gpio_is_valid(panel_enable)) {
+               unsigned long f = GPIOF_OUT_INIT_HIGH;
+               if (flags == OF_GPIO_ACTIVE_LOW)
+                       f = GPIOF_OUT_INIT_LOW;
+               ret = devm_gpio_request_one(&pdev->dev, panel_enable,
+                                           f, "panel-enable");
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "failed to request gpio %d: %d\n",
+                               panel_enable, ret);
+                       goto error_panel_enable;
+               }
+       }
+
        fb_info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
        if (!fb_info->pseudo_palette) {
                ret = -ENOMEM;
@@ -854,6 +899,7 @@ error_register:
 error_init_fb:
        kfree(fb_info->pseudo_palette);
 error_pseudo_pallette:
+error_panel_enable:
        clk_put(host->clk);
 error_getclock:
 error_getpin:
@@ -901,19 +947,6 @@ static void mxsfb_shutdown(struct platform_device *pdev)
        writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
 }
 
-static struct platform_device_id mxsfb_devtype[] = {
-       {
-               .name = "imx23-fb",
-               .driver_data = MXSFB_V3,
-       }, {
-               .name = "imx28-fb",
-               .driver_data = MXSFB_V4,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
-
 static struct platform_driver mxsfb_driver = {
        .probe = mxsfb_probe,
        .remove = __devexit_p(mxsfb_remove),
@@ -921,6 +954,7 @@ static struct platform_driver mxsfb_driver = {
        .id_table = mxsfb_devtype,
        .driver = {
                   .name = DRIVER_NAME,
+                  .of_match_table = mxsfb_dt_ids,
        },
 };
 
index 5066eee10ccf78b641044e4541c022229617dbfc..58bd9c27369df9d4a39d1352f9d9cad74ec51b37 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/io.h>
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
 
 #include <video/omapdss.h>
 
@@ -201,6 +202,28 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
 #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
 
 /* PLATFORM DEVICE */
+static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
+{
+       DSSDBG("pm notif %lu\n", v);
+
+       switch (v) {
+       case PM_SUSPEND_PREPARE:
+               DSSDBG("suspending displays\n");
+               return dss_suspend_all_devices();
+
+       case PM_POST_SUSPEND:
+               DSSDBG("resuming displays\n");
+               return dss_resume_all_devices();
+
+       default:
+               return 0;
+       }
+}
+
+static struct notifier_block omap_dss_pm_notif_block = {
+       .notifier_call = omap_dss_pm_notif,
+};
+
 static int __init omap_dss_probe(struct platform_device *pdev)
 {
        struct omap_dss_board_info *pdata = pdev->dev.platform_data;
@@ -224,6 +247,8 @@ static int __init omap_dss_probe(struct platform_device *pdev)
        else if (pdata->default_device)
                core.default_display_name = pdata->default_device->name;
 
+       register_pm_notifier(&omap_dss_pm_notif_block);
+
        return 0;
 
 err_debugfs:
@@ -233,6 +258,8 @@ err_debugfs:
 
 static int omap_dss_remove(struct platform_device *pdev)
 {
+       unregister_pm_notifier(&omap_dss_pm_notif_block);
+
        dss_uninitialize_debugfs();
 
        dss_uninit_overlays(pdev);
@@ -247,25 +274,9 @@ static void omap_dss_shutdown(struct platform_device *pdev)
        dss_disable_all_devices();
 }
 
-static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       DSSDBG("suspend %d\n", state.event);
-
-       return dss_suspend_all_devices();
-}
-
-static int omap_dss_resume(struct platform_device *pdev)
-{
-       DSSDBG("resume\n");
-
-       return dss_resume_all_devices();
-}
-
 static struct platform_driver omap_dss_driver = {
        .remove         = omap_dss_remove,
        .shutdown       = omap_dss_shutdown,
-       .suspend        = omap_dss_suspend,
-       .resume         = omap_dss_resume,
        .driver         = {
                .name   = "omapdss",
                .owner  = THIS_MODULE,
index 4749ac356469ea8645b3e92c1d72512a102f8e36..397d4eee11bb7715d9d01e3b8a1330abcdc2f2e4 100644 (file)
@@ -384,7 +384,7 @@ void dispc_runtime_put(void)
        DSSDBG("dispc_runtime_put\n");
 
        r = pm_runtime_put_sync(&dispc.pdev->dev);
-       WARN_ON(r < 0);
+       WARN_ON(r < 0 && r != -ENOSYS);
 }
 
 static inline bool dispc_mgr_is_lcd(enum omap_channel channel)
index ca8382d346e9bb0af2d8b749efd0e6d6ae25ff09..14ce8cc079e3d1840e982734b4e2644770ba9b72 100644 (file)
@@ -1075,7 +1075,7 @@ void dsi_runtime_put(struct platform_device *dsidev)
        DSSDBG("dsi_runtime_put\n");
 
        r = pm_runtime_put_sync(&dsi->pdev->dev);
-       WARN_ON(r < 0);
+       WARN_ON(r < 0 && r != -ENOSYS);
 }
 
 /* source clock for DSI PLL. this could also be PCLKFREE */
index 770632359a176b74bd2b62f78bc83a3ac966cbd0..d2b57197b292086cd95a32ef1b33136c0e216166 100644 (file)
@@ -731,7 +731,7 @@ static void dss_runtime_put(void)
        DSSDBG("dss_runtime_put\n");
 
        r = pm_runtime_put_sync(&dss.pdev->dev);
-       WARN_ON(r < 0 && r != -EBUSY);
+       WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
 }
 
 /* DEBUGFS */
index 8195c7166d200c8e575aba54f5e4f46c335df002..26a2430a70288d6cf468357d854fe3429b245f72 100644 (file)
@@ -138,7 +138,7 @@ static void hdmi_runtime_put(void)
        DSSDBG("hdmi_runtime_put\n");
 
        r = pm_runtime_put_sync(&hdmi.pdev->dev);
-       WARN_ON(r < 0);
+       WARN_ON(r < 0 && r != -ENOSYS);
 }
 
 static int __init hdmi_init_display(struct omap_dss_device *dssdev)
index 3d8c206e90e5d93631a0dc493f9ab180fbfa181e..7985fa12b9b46c8c3f6da328f578a76b6267a66e 100644 (file)
@@ -141,7 +141,7 @@ static void rfbi_runtime_put(void)
        DSSDBG("rfbi_runtime_put\n");
 
        r = pm_runtime_put_sync(&rfbi.pdev->dev);
-       WARN_ON(r < 0);
+       WARN_ON(r < 0 && r != -ENOSYS);
 }
 
 void rfbi_bus_lock(void)
index 2b8973931ff48e845cd9a1386b7b437b369b24e4..3907c8b6ecbca991e3cc9313c1a1473c247cb216 100644 (file)
@@ -402,7 +402,7 @@ static void venc_runtime_put(void)
        DSSDBG("venc_runtime_put\n");
 
        r = pm_runtime_put_sync(&venc.pdev->dev);
-       WARN_ON(r < 0);
+       WARN_ON(r < 0 && r != -ENOSYS);
 }
 
 static const struct venc_config *venc_timings_to_config(
index bfbc15ca38ddd3a0ac57cf0860624558a35aee47..0908e604433303d605b9a7cd6ab4ffe36087f96f 100644 (file)
@@ -47,7 +47,7 @@ struct virtio_balloon
        struct task_struct *thread;
 
        /* Waiting for host to ack the pages we released. */
-       struct completion acked;
+       wait_queue_head_t acked;
 
        /* Number of balloon pages we've told the Host we're not using. */
        unsigned int num_pages;
@@ -89,29 +89,25 @@ static struct page *balloon_pfn_to_page(u32 pfn)
 
 static void balloon_ack(struct virtqueue *vq)
 {
-       struct virtio_balloon *vb;
-       unsigned int len;
+       struct virtio_balloon *vb = vq->vdev->priv;
 
-       vb = virtqueue_get_buf(vq, &len);
-       if (vb)
-               complete(&vb->acked);
+       wake_up(&vb->acked);
 }
 
 static void tell_host(struct virtio_balloon *vb, struct virtqueue *vq)
 {
        struct scatterlist sg;
+       unsigned int len;
 
        sg_init_one(&sg, vb->pfns, sizeof(vb->pfns[0]) * vb->num_pfns);
 
-       init_completion(&vb->acked);
-
        /* We should always be able to add one buffer to an empty queue. */
        if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
        virtqueue_kick(vq);
 
        /* When host has read buffer, this completes via balloon_ack */
-       wait_for_completion(&vb->acked);
+       wait_event(vb->acked, virtqueue_get_buf(vq, &len));
 }
 
 static void set_page_pfns(u32 pfns[], struct page *page)
@@ -231,12 +227,8 @@ static void update_balloon_stats(struct virtio_balloon *vb)
  */
 static void stats_request(struct virtqueue *vq)
 {
-       struct virtio_balloon *vb;
-       unsigned int len;
+       struct virtio_balloon *vb = vq->vdev->priv;
 
-       vb = virtqueue_get_buf(vq, &len);
-       if (!vb)
-               return;
        vb->need_stats_update = 1;
        wake_up(&vb->config_change);
 }
@@ -245,11 +237,14 @@ static void stats_handle_request(struct virtio_balloon *vb)
 {
        struct virtqueue *vq;
        struct scatterlist sg;
+       unsigned int len;
 
        vb->need_stats_update = 0;
        update_balloon_stats(vb);
 
        vq = vb->stats_vq;
+       if (!virtqueue_get_buf(vq, &len))
+               return;
        sg_init_one(&sg, vb->stats, sizeof(vb->stats));
        if (virtqueue_add_buf(vq, &sg, 1, 0, vb, GFP_KERNEL) < 0)
                BUG();
@@ -358,6 +353,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
        INIT_LIST_HEAD(&vb->pages);
        vb->num_pages = 0;
        init_waitqueue_head(&vb->config_change);
+       init_waitqueue_head(&vb->acked);
        vb->vdev = vdev;
        vb->need_stats_update = 0;
 
index 8285d65cd2074ff71b954a16e30e39c719808623..02ebfd5f0e6534a5e19536bf5a4115a1e0ed07e4 100644 (file)
@@ -430,6 +430,12 @@ static int omap_wdt_resume(struct platform_device *pdev)
 #define        omap_wdt_resume         NULL
 #endif
 
+static const struct of_device_id omap_wdt_of_match[] = {
+       { .compatible = "ti,omap3-wdt", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, omap_wdt_of_match);
+
 static struct platform_driver omap_wdt_driver = {
        .probe          = omap_wdt_probe,
        .remove         = __devexit_p(omap_wdt_remove),
@@ -439,6 +445,7 @@ static struct platform_driver omap_wdt_driver = {
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "omap_wdt",
+               .of_match_table = omap_wdt_of_match,
        },
 };
 
index e78956cbd7021c81a50d7bd6e9220ffa9623bb22..34c59f14a1c9d9b4deea3f8fa3a55830813d3498 100644 (file)
@@ -144,7 +144,7 @@ extern void v9fs_session_close(struct v9fs_session_info *v9ses);
 extern void v9fs_session_cancel(struct v9fs_session_info *v9ses);
 extern void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
 extern struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
-                       struct nameidata *nameidata);
+                       unsigned int flags);
 extern int v9fs_vfs_unlink(struct inode *i, struct dentry *d);
 extern int v9fs_vfs_rmdir(struct inode *i, struct dentry *d);
 extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
index d529437ff44269f79cb707592a8e504bf4744cea..64600b5d0522c203ac6e8a4043462fe6e513d4aa 100644 (file)
@@ -100,13 +100,13 @@ static void v9fs_dentry_release(struct dentry *dentry)
        }
 }
 
-static int v9fs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct p9_fid *fid;
        struct inode *inode;
        struct v9fs_inode *v9inode;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = dentry->d_inode;
index 57ccb7537dae3064b6892e4f6af6cff8bcada3a6..cbf9dbb1b2a270f4ebd911f7b1aca3d0107969e3 100644 (file)
@@ -712,88 +712,34 @@ error:
 }
 
 /**
- * v9fs_vfs_create - VFS hook to create files
+ * v9fs_vfs_create - VFS hook to create a regular file
+ *
+ * open(.., O_CREAT) is handled in v9fs_vfs_atomic_open().  This is only called
+ * for mknod(2).
+ *
  * @dir: directory inode that is being created
  * @dentry:  dentry that is being deleted
  * @mode: create permissions
- * @nd: path information
  *
  */
 
 static int
 v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
-       int err;
-       u32 perm;
-       int flags;
-       struct file *filp;
-       struct v9fs_inode *v9inode;
-       struct v9fs_session_info *v9ses;
-       struct p9_fid *fid, *inode_fid;
-
-       err = 0;
-       fid = NULL;
-       v9ses = v9fs_inode2v9ses(dir);
-       perm = unixmode2p9mode(v9ses, mode);
-       if (nd)
-               flags = nd->intent.open.flags;
-       else
-               flags = O_RDWR;
+       struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
+       u32 perm = unixmode2p9mode(v9ses, mode);
+       struct p9_fid *fid;
 
-       fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
-                               v9fs_uflags2omode(flags,
-                                               v9fs_proto_dotu(v9ses)));
-       if (IS_ERR(fid)) {
-               err = PTR_ERR(fid);
-               fid = NULL;
-               goto error;
-       }
+       /* P9_OEXCL? */
+       fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);
+       if (IS_ERR(fid))
+               return PTR_ERR(fid);
 
        v9fs_invalidate_inode_attr(dir);
-       /* if we are opening a file, assign the open fid to the file */
-       if (nd) {
-               v9inode = V9FS_I(dentry->d_inode);
-               mutex_lock(&v9inode->v_mutex);
-               if (v9ses->cache && !v9inode->writeback_fid &&
-                   ((flags & O_ACCMODE) != O_RDONLY)) {
-                       /*
-                        * clone a fid and add it to writeback_fid
-                        * we do it during open time instead of
-                        * page dirty time via write_begin/page_mkwrite
-                        * because we want write after unlink usecase
-                        * to work.
-                        */
-                       inode_fid = v9fs_writeback_fid(dentry);
-                       if (IS_ERR(inode_fid)) {
-                               err = PTR_ERR(inode_fid);
-                               mutex_unlock(&v9inode->v_mutex);
-                               goto error;
-                       }
-                       v9inode->writeback_fid = (void *) inode_fid;
-               }
-               mutex_unlock(&v9inode->v_mutex);
-               filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
-               if (IS_ERR(filp)) {
-                       err = PTR_ERR(filp);
-                       goto error;
-               }
-
-               filp->private_data = fid;
-#ifdef CONFIG_9P_FSCACHE
-               if (v9ses->cache)
-                       v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
-#endif
-       } else
-               p9_client_clunk(fid);
+       p9_client_clunk(fid);
 
        return 0;
-
-error:
-       if (fid)
-               p9_client_clunk(fid);
-
-       return err;
 }
 
 /**
@@ -839,7 +785,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
  */
 
 struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
-                                     struct nameidata *nameidata)
+                                     unsigned int flags)
 {
        struct dentry *res;
        struct super_block *sb;
@@ -849,8 +795,8 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
        char *name;
        int result = 0;
 
-       p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
-                dir, dentry->d_name.name, dentry, nameidata);
+       p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n",
+                dir, dentry->d_name.name, dentry, flags);
 
        if (dentry->d_name.len > NAME_MAX)
                return ERR_PTR(-ENAMETOOLONG);
@@ -910,6 +856,86 @@ error:
        return ERR_PTR(result);
 }
 
+static int
+v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
+                    struct file *file, unsigned flags, umode_t mode,
+                    int *opened)
+{
+       int err;
+       u32 perm;
+       struct v9fs_inode *v9inode;
+       struct v9fs_session_info *v9ses;
+       struct p9_fid *fid, *inode_fid;
+       struct dentry *res = NULL;
+
+       if (d_unhashed(dentry)) {
+               res = v9fs_vfs_lookup(dir, dentry, 0);
+               if (IS_ERR(res))
+                       return PTR_ERR(res);
+
+               if (res)
+                       dentry = res;
+       }
+
+       /* Only creates */
+       if (!(flags & O_CREAT) || dentry->d_inode)
+               return finish_no_open(file, res);
+
+       err = 0;
+       fid = NULL;
+       v9ses = v9fs_inode2v9ses(dir);
+       perm = unixmode2p9mode(v9ses, mode);
+       fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
+                               v9fs_uflags2omode(flags,
+                                               v9fs_proto_dotu(v9ses)));
+       if (IS_ERR(fid)) {
+               err = PTR_ERR(fid);
+               fid = NULL;
+               goto error;
+       }
+
+       v9fs_invalidate_inode_attr(dir);
+       v9inode = V9FS_I(dentry->d_inode);
+       mutex_lock(&v9inode->v_mutex);
+       if (v9ses->cache && !v9inode->writeback_fid &&
+           ((flags & O_ACCMODE) != O_RDONLY)) {
+               /*
+                * clone a fid and add it to writeback_fid
+                * we do it during open time instead of
+                * page dirty time via write_begin/page_mkwrite
+                * because we want write after unlink usecase
+                * to work.
+                */
+               inode_fid = v9fs_writeback_fid(dentry);
+               if (IS_ERR(inode_fid)) {
+                       err = PTR_ERR(inode_fid);
+                       mutex_unlock(&v9inode->v_mutex);
+                       goto error;
+               }
+               v9inode->writeback_fid = (void *) inode_fid;
+       }
+       mutex_unlock(&v9inode->v_mutex);
+       err = finish_open(file, dentry, generic_file_open, opened);
+       if (err)
+               goto error;
+
+       file->private_data = fid;
+#ifdef CONFIG_9P_FSCACHE
+       if (v9ses->cache)
+               v9fs_cache_inode_set_cookie(dentry->d_inode, file);
+#endif
+
+       *opened |= FILE_CREATED;
+out:
+       dput(res);
+       return err;
+
+error:
+       if (fid)
+               p9_client_clunk(fid);
+       goto out;
+}
+
 /**
  * v9fs_vfs_unlink - VFS unlink hook to delete an inode
  * @i:  inode that is being unlinked
@@ -1488,6 +1514,7 @@ out:
 static const struct inode_operations v9fs_dir_inode_operations_dotu = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
+       .atomic_open = v9fs_vfs_atomic_open,
        .symlink = v9fs_vfs_symlink,
        .link = v9fs_vfs_link,
        .unlink = v9fs_vfs_unlink,
@@ -1502,6 +1529,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
 static const struct inode_operations v9fs_dir_inode_operations = {
        .create = v9fs_vfs_create,
        .lookup = v9fs_vfs_lookup,
+       .atomic_open = v9fs_vfs_atomic_open,
        .unlink = v9fs_vfs_unlink,
        .mkdir = v9fs_vfs_mkdir,
        .rmdir = v9fs_vfs_rmdir,
index e3dd2a1e2bfc18e47abae82bce7ee60238527c08..40895546e103e3e9b35e9542e23ac929d74de348 100644 (file)
@@ -230,20 +230,25 @@ int v9fs_open_to_dotl_flags(int flags)
  * @dir: directory inode that is being created
  * @dentry:  dentry that is being deleted
  * @mode: create permissions
- * @nd: path information
  *
  */
 
 static int
 v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
-               struct nameidata *nd)
+               bool excl)
+{
+       return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
+}
+
+static int
+v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
+                         struct file *file, unsigned flags, umode_t omode,
+                         int *opened)
 {
        int err = 0;
        gid_t gid;
-       int flags;
        umode_t mode;
        char *name = NULL;
-       struct file *filp;
        struct p9_qid qid;
        struct inode *inode;
        struct p9_fid *fid = NULL;
@@ -251,19 +256,23 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        struct p9_fid *dfid, *ofid, *inode_fid;
        struct v9fs_session_info *v9ses;
        struct posix_acl *pacl = NULL, *dacl = NULL;
+       struct dentry *res = NULL;
 
-       v9ses = v9fs_inode2v9ses(dir);
-       if (nd)
-               flags = nd->intent.open.flags;
-       else {
-               /*
-                * create call without LOOKUP_OPEN is due
-                * to mknod of regular files. So use mknod
-                * operation.
-                */
-               return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
+       if (d_unhashed(dentry)) {
+               res = v9fs_vfs_lookup(dir, dentry, 0);
+               if (IS_ERR(res))
+                       return PTR_ERR(res);
+
+               if (res)
+                       dentry = res;
        }
 
+       /* Only creates */
+       if (!(flags & O_CREAT) || dentry->d_inode)
+               return finish_no_open(file, res);
+
+       v9ses = v9fs_inode2v9ses(dir);
+
        name = (char *) dentry->d_name.name;
        p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
                 name, flags, omode);
@@ -272,7 +281,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        if (IS_ERR(dfid)) {
                err = PTR_ERR(dfid);
                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
-               return err;
+               goto out;
        }
 
        /* clone a fid to use for creation */
@@ -280,7 +289,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        if (IS_ERR(ofid)) {
                err = PTR_ERR(ofid);
                p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
-               return err;
+               goto out;
        }
 
        gid = v9fs_get_fsgid_for_create(dir);
@@ -345,17 +354,18 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
        }
        mutex_unlock(&v9inode->v_mutex);
        /* Since we are opening a file, assign the open fid to the file */
-       filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
-       if (IS_ERR(filp)) {
-               err = PTR_ERR(filp);
+       err = finish_open(file, dentry, generic_file_open, opened);
+       if (err)
                goto err_clunk_old_fid;
-       }
-       filp->private_data = ofid;
+       file->private_data = ofid;
 #ifdef CONFIG_9P_FSCACHE
        if (v9ses->cache)
-               v9fs_cache_inode_set_cookie(inode, filp);
+               v9fs_cache_inode_set_cookie(inode, file);
 #endif
-       return 0;
+       *opened |= FILE_CREATED;
+out:
+       dput(res);
+       return err;
 
 error:
        if (fid)
@@ -364,7 +374,7 @@ err_clunk_old_fid:
        if (ofid)
                p9_client_clunk(ofid);
        v9fs_set_create_acl(NULL, &dacl, &pacl);
-       return err;
+       goto out;
 }
 
 /**
@@ -982,6 +992,7 @@ out:
 
 const struct inode_operations v9fs_dir_inode_operations_dotl = {
        .create = v9fs_vfs_create_dotl,
+       .atomic_open = v9fs_vfs_atomic_open_dotl,
        .lookup = v9fs_vfs_lookup,
        .link = v9fs_vfs_link_dotl,
        .symlink = v9fs_vfs_symlink_dotl,
index 8c92a9ba83306576ef45f4abe217b92954d4c05e..137d50396898e490937349998282a86ab0ed4f4d 100644 (file)
@@ -89,7 +89,7 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
        if (v9ses->cache)
                sb->s_bdi->ra_pages = (VM_MAX_READAHEAD * 1024)/PAGE_CACHE_SIZE;
 
-       sb->s_flags = flags | MS_ACTIVE | MS_DIRSYNC | MS_NOATIME;
+       sb->s_flags |= MS_ACTIVE | MS_DIRSYNC | MS_NOATIME;
        if (!v9ses->cache)
                sb->s_flags |= MS_SYNCHRONOUS;
 
@@ -137,7 +137,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
                goto close_session;
        }
 
-       sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
+       sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses);
        if (IS_ERR(sb)) {
                retval = PTR_ERR(sb);
                goto clunk_fid;
index 3d83075aaa2e472dc2de5c0a34f249b3af2be012..b3be2e7c56436f006254d30724463cf8b05d0033 100644 (file)
@@ -266,7 +266,7 @@ const struct dentry_operations adfs_dentry_operations = {
 };
 
 static struct dentry *
-adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode = NULL;
        struct object_info obj;
index 06fdcc9382c4d27d2effb1595b7480a402eaf7e9..bdaec92353c2cc0e5e876115ee7a474e45c0ba4b 100644 (file)
@@ -246,7 +246,6 @@ static struct inode *adfs_alloc_inode(struct super_block *sb)
 static void adfs_i_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
-       INIT_LIST_HEAD(&inode->i_dentry);
        kmem_cache_free(adfs_inode_cachep, ADFS_I(inode));
 }
 
index 1fceb320d2f22c16bc1a900cb27597d68977dbbd..6e216419f340de5219a684db6a70f99643784ac5 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/buffer_head.h>
 #include <linux/amigaffs.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
 
 /* AmigaOS allows file names with up to 30 characters length.
  * Names longer than that will be silently truncated. If you
@@ -100,6 +101,10 @@ struct affs_sb_info {
        char *s_prefix;                 /* Prefix for volumes and assigns. */
        char s_volume[32];              /* Volume prefix for absolute symlinks. */
        spinlock_t symlink_lock;        /* protects the previous two */
+       struct super_block *sb;         /* the VFS superblock object */
+       int work_queued;                /* non-zero delayed work is queued */
+       struct delayed_work sb_work;    /* superblock flush delayed work */
+       spinlock_t work_lock;           /* protects sb_work and work_queued */
 };
 
 #define SF_INTL                0x0001          /* International filesystem. */
@@ -120,6 +125,8 @@ static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)
        return sb->s_fs_info;
 }
 
+void affs_mark_sb_dirty(struct super_block *sb);
+
 /* amigaffs.c */
 
 extern int     affs_insert_hash(struct inode *inode, struct buffer_head *bh);
@@ -146,9 +153,9 @@ extern void affs_free_bitmap(struct super_block *sb);
 /* namei.c */
 
 extern int     affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len);
-extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *);
+extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int);
 extern int     affs_unlink(struct inode *dir, struct dentry *dentry);
-extern int     affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *);
+extern int     affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool);
 extern int     affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 extern int     affs_rmdir(struct inode *dir, struct dentry *dentry);
 extern int     affs_link(struct dentry *olddentry, struct inode *dir,
index 52a6407682e65e1aa0c82805c2d052cc09b20361..eb82ee53ee0be25a3c805c85ac9dd6c4028753b4 100644 (file)
@@ -122,22 +122,16 @@ affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
 }
 
 static void
-affs_fix_dcache(struct dentry *dentry, u32 entry_ino)
+affs_fix_dcache(struct inode *inode, u32 entry_ino)
 {
-       struct inode *inode = dentry->d_inode;
-       void *data = dentry->d_fsdata;
-       struct list_head *head, *next;
-
+       struct dentry *dentry;
+       struct hlist_node *p;
        spin_lock(&inode->i_lock);
-       head = &inode->i_dentry;
-       next = head->next;
-       while (next != head) {
-               dentry = list_entry(next, struct dentry, d_alias);
+       hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
                if (entry_ino == (u32)(long)dentry->d_fsdata) {
-                       dentry->d_fsdata = data;
+                       dentry->d_fsdata = (void *)inode->i_ino;
                        break;
                }
-               next = next->next;
        }
        spin_unlock(&inode->i_lock);
 }
@@ -177,7 +171,11 @@ affs_remove_link(struct dentry *dentry)
                }
 
                affs_lock_dir(dir);
-               affs_fix_dcache(dentry, link_ino);
+               /*
+                * if there's a dentry for that block, make it
+                * refer to inode itself.
+                */
+               affs_fix_dcache(inode, link_ino);
                retval = affs_remove_hash(dir, link_bh);
                if (retval) {
                        affs_unlock_dir(dir);
index 3e262711ae06edfc0202e0914bd1627c1ccb643f..6e0be43ef6ef8eef90c57a4560bf671c9d756b7a 100644 (file)
@@ -103,7 +103,7 @@ affs_free_block(struct super_block *sb, u32 block)
        *(__be32 *)bh->b_data = cpu_to_be32(tmp - mask);
 
        mark_buffer_dirty(bh);
-       sb->s_dirt = 1;
+       affs_mark_sb_dirty(sb);
        bm->bm_free++;
 
        mutex_unlock(&sbi->s_bmlock);
@@ -248,7 +248,7 @@ find_bit:
        *(__be32 *)bh->b_data = cpu_to_be32(tmp + mask);
 
        mark_buffer_dirty(bh);
-       sb->s_dirt = 1;
+       affs_mark_sb_dirty(sb);
 
        mutex_unlock(&sbi->s_bmlock);
 
index 47806940aac0a9d003987cbdf4f9a0b0af6c5f47..ff65884a7839974ca472a64097ac996245c96346 100644 (file)
@@ -211,7 +211,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry)
 }
 
 struct dentry *
-affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct super_block *sb = dir->i_sb;
        struct buffer_head *bh;
@@ -255,7 +255,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
 }
 
 int
-affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
        struct super_block *sb = dir->i_sb;
        struct inode    *inode;
index 0782653a05a2d2d9098057572605fa75ef9900f3..c70f1e5fc0247a616d44e60c2681bbf8fc14c747 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/magic.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/writeback.h>
 #include "affs.h"
 
 extern struct timezone sys_tz;
@@ -25,15 +26,17 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf);
 static int affs_remount (struct super_block *sb, int *flags, char *data);
 
 static void
-affs_commit_super(struct super_block *sb, int wait, int clean)
+affs_commit_super(struct super_block *sb, int wait)
 {
        struct affs_sb_info *sbi = AFFS_SB(sb);
        struct buffer_head *bh = sbi->s_root_bh;
        struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh);
 
-       tail->bm_flag = cpu_to_be32(clean);
+       lock_buffer(bh);
        secs_to_datestamp(get_seconds(), &tail->disk_change);
        affs_fix_checksum(sb, bh);
+       unlock_buffer(bh);
+
        mark_buffer_dirty(bh);
        if (wait)
                sync_dirty_buffer(bh);
@@ -45,9 +48,7 @@ affs_put_super(struct super_block *sb)
        struct affs_sb_info *sbi = AFFS_SB(sb);
        pr_debug("AFFS: put_super()\n");
 
-       if (!(sb->s_flags & MS_RDONLY) && sb->s_dirt)
-               affs_commit_super(sb, 1, 1);
-
+       cancel_delayed_work_sync(&sbi->sb_work);
        kfree(sbi->s_prefix);
        affs_free_bitmap(sb);
        affs_brelse(sbi->s_root_bh);
@@ -55,26 +56,43 @@ affs_put_super(struct super_block *sb)
        sb->s_fs_info = NULL;
 }
 
-static void
-affs_write_super(struct super_block *sb)
+static int
+affs_sync_fs(struct super_block *sb, int wait)
 {
-       lock_super(sb);
-       if (!(sb->s_flags & MS_RDONLY))
-               affs_commit_super(sb, 1, 2);
-       sb->s_dirt = 0;
-       unlock_super(sb);
+       affs_commit_super(sb, wait);
+       return 0;
+}
+
+static void flush_superblock(struct work_struct *work)
+{
+       struct affs_sb_info *sbi;
+       struct super_block *sb;
+
+       sbi = container_of(work, struct affs_sb_info, sb_work.work);
+       sb = sbi->sb;
 
-       pr_debug("AFFS: write_super() at %lu, clean=2\n", get_seconds());
+       spin_lock(&sbi->work_lock);
+       sbi->work_queued = 0;
+       spin_unlock(&sbi->work_lock);
+
+       affs_commit_super(sb, 1);
 }
 
-static int
-affs_sync_fs(struct super_block *sb, int wait)
+void affs_mark_sb_dirty(struct super_block *sb)
 {
-       lock_super(sb);
-       affs_commit_super(sb, wait, 2);
-       sb->s_dirt = 0;
-       unlock_super(sb);
-       return 0;
+       struct affs_sb_info *sbi = AFFS_SB(sb);
+       unsigned long delay;
+
+       if (sb->s_flags & MS_RDONLY)
+              return;
+
+       spin_lock(&sbi->work_lock);
+       if (!sbi->work_queued) {
+              delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+              queue_delayed_work(system_long_wq, &sbi->sb_work, delay);
+              sbi->work_queued = 1;
+       }
+       spin_unlock(&sbi->work_lock);
 }
 
 static struct kmem_cache * affs_inode_cachep;
@@ -138,7 +156,6 @@ static const struct super_operations affs_sops = {
        .write_inode    = affs_write_inode,
        .evict_inode    = affs_evict_inode,
        .put_super      = affs_put_super,
-       .write_super    = affs_write_super,
        .sync_fs        = affs_sync_fs,
        .statfs         = affs_statfs,
        .remount_fs     = affs_remount,
@@ -305,8 +322,11 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
 
        sb->s_fs_info = sbi;
+       sbi->sb = sb;
        mutex_init(&sbi->s_bmlock);
        spin_lock_init(&sbi->symlink_lock);
+       spin_lock_init(&sbi->work_lock);
+       INIT_DELAYED_WORK(&sbi->sb_work, flush_superblock);
 
        if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
                                &blocksize,&sbi->s_prefix,
@@ -531,6 +551,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
                return -EINVAL;
        }
 
+       flush_delayed_work_sync(&sbi->sb_work);
        replace_mount_options(sb, new_opts);
 
        sbi->s_flags = mount_flags;
@@ -549,10 +570,9 @@ affs_remount(struct super_block *sb, int *flags, char *data)
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
                return 0;
 
-       if (*flags & MS_RDONLY) {
-               affs_write_super(sb);
+       if (*flags & MS_RDONLY)
                affs_free_bitmap(sb);
-       else
+       else
                res = affs_init_bitmap(sb, flags);
 
        return res;
index e22dc4b4a503e58926b89314aef6889bd26dad82..db477906ba4f441acd9fc100be2668e7894a7c88 100644 (file)
 #include "internal.h"
 
 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
-                                struct nameidata *nd);
+                                unsigned int flags);
 static int afs_dir_open(struct inode *inode, struct file *file);
 static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
-static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
+static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
 static int afs_d_delete(const struct dentry *dentry);
 static void afs_d_release(struct dentry *dentry);
 static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
                                  loff_t fpos, u64 ino, unsigned dtype);
 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                     struct nameidata *nd);
+                     bool excl);
 static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 static int afs_rmdir(struct inode *dir, struct dentry *dentry);
 static int afs_unlink(struct inode *dir, struct dentry *dentry);
@@ -516,7 +516,7 @@ out:
  * look up an entry in a directory
  */
 static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
-                                struct nameidata *nd)
+                                unsigned int flags)
 {
        struct afs_vnode *vnode;
        struct afs_fid fid;
@@ -598,7 +598,7 @@ success:
  * - NOTE! the hit can be a negative hit too, so we can't assume we have an
  *   inode
  */
-static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct afs_vnode *vnode, *dir;
        struct afs_fid uninitialized_var(fid);
@@ -607,7 +607,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
        void *dir_version;
        int ret;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        vnode = AFS_FS_I(dentry->d_inode);
@@ -949,7 +949,7 @@ error:
  * create a regular file on an AFS filesystem
  */
 static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                     struct nameidata *nd)
+                     bool excl)
 {
        struct afs_file_status status;
        struct afs_callback cb;
index 298cf8919ec79b547db2a80b80a87697c705442f..9682c33d5daf44d66351ca29ebb5c02cb39ca1ae 100644 (file)
@@ -22,7 +22,7 @@
 
 static struct dentry *afs_mntpt_lookup(struct inode *dir,
                                       struct dentry *dentry,
-                                      struct nameidata *nd);
+                                      unsigned int flags);
 static int afs_mntpt_open(struct inode *inode, struct file *file);
 static void afs_mntpt_expiry_timed_out(struct work_struct *work);
 
@@ -104,7 +104,7 @@ out:
  */
 static struct dentry *afs_mntpt_lookup(struct inode *dir,
                                       struct dentry *dentry,
-                                      struct nameidata *nd)
+                                      unsigned int flags)
 {
        _enter("%p,%p{%p{%s},%s}",
               dir,
index f02b31e7e648ff67007990626b8b9f2641f694f3..df8c6047c2a12c41e5cd2935066e9b0397226d9a 100644 (file)
@@ -395,7 +395,7 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
        as->volume = vol;
 
        /* allocate a deviceless superblock */
-       sb = sget(fs_type, afs_test_super, afs_set_super, as);
+       sb = sget(fs_type, afs_test_super, afs_set_super, flags, as);
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
                afs_put_volume(vol);
@@ -406,7 +406,6 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
        if (!sb->s_root) {
                /* initial superblock/root creation */
                _debug("create");
-               sb->s_flags = flags;
                ret = afs_fill_super(sb, &params);
                if (ret < 0) {
                        deactivate_locked_super(sb);
index 55c4c76560537f7fe72d6ff5f429eff666b86789..71f613cf4a85a36e08044840f65b36b0c9fc4579 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -56,13 +56,6 @@ static struct kmem_cache     *kioctx_cachep;
 
 static struct workqueue_struct *aio_wq;
 
-/* Used for rare fput completion. */
-static void aio_fput_routine(struct work_struct *);
-static DECLARE_WORK(fput_work, aio_fput_routine);
-
-static DEFINE_SPINLOCK(fput_lock);
-static LIST_HEAD(fput_head);
-
 static void aio_kick_handler(struct work_struct *);
 static void aio_queue_work(struct kioctx *);
 
@@ -479,7 +472,6 @@ static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
 {
        unsigned short allocated, to_alloc;
        long avail;
-       bool called_fput = false;
        struct kiocb *req, *n;
        struct aio_ring *ring;
 
@@ -495,28 +487,11 @@ static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
        if (allocated == 0)
                goto out;
 
-retry:
        spin_lock_irq(&ctx->ctx_lock);
        ring = kmap_atomic(ctx->ring_info.ring_pages[0]);
 
        avail = aio_ring_avail(&ctx->ring_info, ring) - ctx->reqs_active;
        BUG_ON(avail < 0);
-       if (avail == 0 && !called_fput) {
-               /*
-                * Handle a potential starvation case.  It is possible that
-                * we hold the last reference on a struct file, causing us
-                * to delay the final fput to non-irq context.  In this case,
-                * ctx->reqs_active is artificially high.  Calling the fput
-                * routine here may free up a slot in the event completion
-                * ring, allowing this allocation to succeed.
-                */
-               kunmap_atomic(ring);
-               spin_unlock_irq(&ctx->ctx_lock);
-               aio_fput_routine(NULL);
-               called_fput = true;
-               goto retry;
-       }
-
        if (avail < allocated) {
                /* Trim back the number of requests. */
                list_for_each_entry_safe(req, n, &batch->head, ki_batch) {
@@ -570,36 +545,6 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
                wake_up_all(&ctx->wait);
 }
 
-static void aio_fput_routine(struct work_struct *data)
-{
-       spin_lock_irq(&fput_lock);
-       while (likely(!list_empty(&fput_head))) {
-               struct kiocb *req = list_kiocb(fput_head.next);
-               struct kioctx *ctx = req->ki_ctx;
-
-               list_del(&req->ki_list);
-               spin_unlock_irq(&fput_lock);
-
-               /* Complete the fput(s) */
-               if (req->ki_filp != NULL)
-                       fput(req->ki_filp);
-
-               /* Link the iocb into the context's free list */
-               rcu_read_lock();
-               spin_lock_irq(&ctx->ctx_lock);
-               really_put_req(ctx, req);
-               /*
-                * at that point ctx might've been killed, but actual
-                * freeing is RCU'd
-                */
-               spin_unlock_irq(&ctx->ctx_lock);
-               rcu_read_unlock();
-
-               spin_lock_irq(&fput_lock);
-       }
-       spin_unlock_irq(&fput_lock);
-}
-
 /* __aio_put_req
  *     Returns true if this put was the last user of the request.
  */
@@ -618,21 +563,9 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
        req->ki_cancel = NULL;
        req->ki_retry = NULL;
 
-       /*
-        * Try to optimize the aio and eventfd file* puts, by avoiding to
-        * schedule work in case it is not final fput() time. In normal cases,
-        * we would not be holding the last reference to the file*, so
-        * this function will be executed w/out any aio kthread wakeup.
-        */
-       if (unlikely(!fput_atomic(req->ki_filp))) {
-               spin_lock(&fput_lock);
-               list_add(&req->ki_list, &fput_head);
-               spin_unlock(&fput_lock);
-               schedule_work(&fput_work);
-       } else {
-               req->ki_filp = NULL;
-               really_put_req(ctx, req);
-       }
+       fput(req->ki_filp);
+       req->ki_filp = NULL;
+       really_put_req(ctx, req);
        return 1;
 }
 
index 0da90951d2776f827a905337938399ada79e8e69..29e38a1f7f77a15100f1d20b3e51507470273633 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -171,6 +171,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
        struct timespec now;
        unsigned int ia_valid = attr->ia_valid;
 
+       WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
+
        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
                if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                        return -EPERM;
@@ -250,5 +252,4 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
 
        return error;
 }
-
 EXPORT_SYMBOL(notify_change);
index aa9103f8f01bf8d3bad8d0dcbcc8036895226e3f..abf645c1703bab0036dcb76db1acb570590a3cd5 100644 (file)
@@ -257,8 +257,8 @@ static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid)
                 * corresponding to the autofs fs we want to open.
                 */
 
-               filp = dentry_open(path.dentry, path.mnt, O_RDONLY,
-                                  current_cred());
+               filp = dentry_open(&path, O_RDONLY, current_cred());
+               path_put(&path);
                if (IS_ERR(filp)) {
                        err = PTR_ERR(filp);
                        goto out;
index 75e5f1c8e028fc9663eaed4c24ed5958ca8a0a68..e7396cfdb10999b453567231e433451cb6aecc2f 100644 (file)
@@ -32,7 +32,7 @@ static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long);
 static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
 #endif
 static int autofs4_dir_open(struct inode *inode, struct file *file);
-static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
+static struct dentry *autofs4_lookup(struct inode *,struct dentry *, unsigned int);
 static struct vfsmount *autofs4_d_automount(struct path *);
 static int autofs4_d_manage(struct dentry *, bool);
 static void autofs4_dentry_release(struct dentry *);
@@ -458,7 +458,7 @@ int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
 }
 
 /* Lookups in the root directory */
-static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct autofs_sb_info *sbi;
        struct autofs_info *ino;
index 1b35d6bd06b06d071f8b24e28ece1aa97d87d1ce..b1342ffb3cf6e595125252ac82d5bd54ebbe9544 100644 (file)
@@ -173,13 +173,13 @@ static const struct file_operations bad_file_ops =
 };
 
 static int bad_inode_create (struct inode *dir, struct dentry *dentry,
-               umode_t mode, struct nameidata *nd)
+               umode_t mode, bool excl)
 {
        return -EIO;
 }
 
 static struct dentry *bad_inode_lookup(struct inode *dir,
-                       struct dentry *dentry, struct nameidata *nd)
+                       struct dentry *dentry, unsigned int flags)
 {
        return ERR_PTR(-EIO);
 }
index e18da23d42b5b163cb3a7f3dd8da9cdf76f9774d..cf7f3c67c8b7848e6e8e55b83c3c76bde007f60a 100644 (file)
@@ -34,7 +34,7 @@ static int befs_readdir(struct file *, void *, filldir_t);
 static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 static int befs_readpage(struct file *file, struct page *page);
 static sector_t befs_bmap(struct address_space *mapping, sector_t block);
-static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry *befs_lookup(struct inode *, struct dentry *, unsigned int);
 static struct inode *befs_iget(struct super_block *, unsigned long);
 static struct inode *befs_alloc_inode(struct super_block *sb);
 static void befs_destroy_inode(struct inode *inode);
@@ -159,7 +159,7 @@ befs_get_block(struct inode *inode, sector_t block,
 }
 
 static struct dentry *
-befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode = NULL;
        struct super_block *sb = dir->i_sb;
index d12c7966db27faba8e118f874335bc25b24f3917..2785ef91191ad07c76bbec51a742e0a43fee8be6 100644 (file)
@@ -85,7 +85,7 @@ const struct file_operations bfs_dir_operations = {
 extern void dump_imap(const char *, struct super_block *);
 
 static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                                               struct nameidata *nd)
+                                               bool excl)
 {
        int err;
        struct inode *inode;
@@ -133,7 +133,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 }
 
 static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry,
-                                               struct nameidata *nd)
+                                               unsigned int flags)
 {
        struct inode *inode = NULL;
        struct buffer_head *bh;
index c2bbe1fb132632c14ebb2ea0675ad78500441a52..1e519195d45bd1ab466f8b7ee12505f35a45d271 100644 (file)
@@ -1710,3 +1710,39 @@ int __invalidate_device(struct block_device *bdev, bool kill_dirty)
        return res;
 }
 EXPORT_SYMBOL(__invalidate_device);
+
+void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg)
+{
+       struct inode *inode, *old_inode = NULL;
+
+       spin_lock(&inode_sb_list_lock);
+       list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) {
+               struct address_space *mapping = inode->i_mapping;
+
+               spin_lock(&inode->i_lock);
+               if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
+                   mapping->nrpages == 0) {
+                       spin_unlock(&inode->i_lock);
+                       continue;
+               }
+               __iget(inode);
+               spin_unlock(&inode->i_lock);
+               spin_unlock(&inode_sb_list_lock);
+               /*
+                * We hold a reference to 'inode' so it couldn't have been
+                * removed from s_inodes list while we dropped the
+                * inode_sb_list_lock.  We cannot iput the inode now as we can
+                * be holding the last reference and we cannot iput it under
+                * inode_sb_list_lock. So we keep the reference and iput it
+                * later.
+                */
+               iput(old_inode);
+               old_inode = inode;
+
+               func(I_BDEV(inode), arg);
+
+               spin_lock(&inode_sb_list_lock);
+       }
+       spin_unlock(&inode_sb_list_lock);
+       iput(old_inode);
+}
index 7301cdb4b2cb3cf6c5d8626b2275a85f88d4f55f..a383c18e74e86eebaa847d756e3493e7ca3c9bfd 100644 (file)
@@ -301,10 +301,14 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
                goto out;
 
        eb = path->nodes[level];
-       if (!eb) {
-               WARN_ON(1);
-               ret = 1;
-               goto out;
+       while (!eb) {
+               if (!level) {
+                       WARN_ON(1);
+                       ret = 1;
+                       goto out;
+               }
+               level--;
+               eb = path->nodes[level];
        }
 
        ret = add_all_parents(root, path, parents, level, &ref->key_for_search,
@@ -835,6 +839,7 @@ again:
                        }
                        ret = __add_delayed_refs(head, delayed_ref_seq,
                                                 &prefs_delayed);
+                       mutex_unlock(&head->mutex);
                        if (ret) {
                                spin_unlock(&delayed_refs->lock);
                                goto out;
@@ -928,8 +933,6 @@ again:
        }
 
 out:
-       if (head)
-               mutex_unlock(&head->mutex);
        btrfs_free_path(path);
        while (!list_empty(&prefs)) {
                ref = list_first_entry(&prefs, struct __prelim_ref, list);
index 15cbc2bf4ff0ed11f8bb2e163bc1960c65b27fa7..8206b3900587efa23570b5b8f7f8071ab6e73156 100644 (file)
@@ -1024,11 +1024,18 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
                if (!looped && !tm)
                        return 0;
                /*
-                * we must have key remove operations in the log before the
-                * replace operation.
+                * if there are no tree operation for the oldest root, we simply
+                * return it. this should only happen if that (old) root is at
+                * level 0.
                 */
-               BUG_ON(!tm);
+               if (!tm)
+                       break;
 
+               /*
+                * if there's an operation that's not a root replacement, we
+                * found the oldest version of our root. normally, we'll find a
+                * MOD_LOG_KEY_REMOVE_WHILE_FREEING operation here.
+                */
                if (tm->op != MOD_LOG_ROOT_REPLACE)
                        break;
 
@@ -1087,11 +1094,7 @@ __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq,
                                                      tm->generation);
                        break;
                case MOD_LOG_KEY_ADD:
-                       if (tm->slot != n - 1) {
-                               o_dst = btrfs_node_key_ptr_offset(tm->slot);
-                               o_src = btrfs_node_key_ptr_offset(tm->slot + 1);
-                               memmove_extent_buffer(eb, o_dst, o_src, p_size);
-                       }
+                       /* if a move operation is needed it's in the log */
                        n--;
                        break;
                case MOD_LOG_MOVE_KEYS:
@@ -1192,16 +1195,8 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
        }
 
        tm = tree_mod_log_search(root->fs_info, logical, time_seq);
-       /*
-        * there was an item in the log when __tree_mod_log_oldest_root
-        * returned. this one must not go away, because the time_seq passed to
-        * us must be blocking its removal.
-        */
-       BUG_ON(!tm);
-
        if (old_root)
-               eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT,
-                                              root->nodesize);
+               eb = alloc_dummy_extent_buffer(logical, root->nodesize);
        else
                eb = btrfs_clone_extent_buffer(root->node);
        btrfs_tree_read_unlock(root->node);
@@ -1216,7 +1211,10 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
                btrfs_set_header_level(eb, old_root->level);
                btrfs_set_header_generation(eb, old_generation);
        }
-       __tree_mod_log_rewind(eb, time_seq, tm);
+       if (tm)
+               __tree_mod_log_rewind(eb, time_seq, tm);
+       else
+               WARN_ON(btrfs_header_level(eb) != 0);
        extent_buffer_get(eb);
 
        return eb;
@@ -2995,7 +2993,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
 static void insert_ptr(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct btrfs_path *path,
                       struct btrfs_disk_key *key, u64 bytenr,
-                      int slot, int level, int tree_mod_log)
+                      int slot, int level)
 {
        struct extent_buffer *lower;
        int nritems;
@@ -3008,7 +3006,7 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
        BUG_ON(slot > nritems);
        BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(root));
        if (slot != nritems) {
-               if (tree_mod_log && level)
+               if (level)
                        tree_mod_log_eb_move(root->fs_info, lower, slot + 1,
                                             slot, nritems - slot);
                memmove_extent_buffer(lower,
@@ -3016,7 +3014,7 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
                              btrfs_node_key_ptr_offset(slot),
                              (nritems - slot) * sizeof(struct btrfs_key_ptr));
        }
-       if (tree_mod_log && level) {
+       if (level) {
                ret = tree_mod_log_insert_key(root->fs_info, lower, slot,
                                              MOD_LOG_KEY_ADD);
                BUG_ON(ret < 0);
@@ -3104,7 +3102,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(split);
 
        insert_ptr(trans, root, path, &disk_key, split->start,
-                  path->slots[level + 1] + 1, level + 1, 1);
+                  path->slots[level + 1] + 1, level + 1);
 
        if (path->slots[level] >= mid) {
                path->slots[level] -= mid;
@@ -3641,7 +3639,7 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,
        btrfs_set_header_nritems(l, mid);
        btrfs_item_key(right, &disk_key, 0);
        insert_ptr(trans, root, path, &disk_key, right->start,
-                  path->slots[1] + 1, 1, 0);
+                  path->slots[1] + 1, 1);
 
        btrfs_mark_buffer_dirty(right);
        btrfs_mark_buffer_dirty(l);
@@ -3848,7 +3846,7 @@ again:
                if (mid <= slot) {
                        btrfs_set_header_nritems(right, 0);
                        insert_ptr(trans, root, path, &disk_key, right->start,
-                                  path->slots[1] + 1, 1, 0);
+                                  path->slots[1] + 1, 1);
                        btrfs_tree_unlock(path->nodes[0]);
                        free_extent_buffer(path->nodes[0]);
                        path->nodes[0] = right;
@@ -3857,7 +3855,7 @@ again:
                } else {
                        btrfs_set_header_nritems(right, 0);
                        insert_ptr(trans, root, path, &disk_key, right->start,
-                                         path->slots[1], 1, 0);
+                                         path->slots[1], 1);
                        btrfs_tree_unlock(path->nodes[0]);
                        free_extent_buffer(path->nodes[0]);
                        path->nodes[0] = right;
@@ -5121,6 +5119,18 @@ again:
 
                if (!path->skip_locking) {
                        ret = btrfs_try_tree_read_lock(next);
+                       if (!ret && time_seq) {
+                               /*
+                                * If we don't get the lock, we may be racing
+                                * with push_leaf_left, holding that lock while
+                                * itself waiting for the leaf we've currently
+                                * locked. To solve this situation, we give up
+                                * on our lock and cycle.
+                                */
+                               btrfs_release_path(path);
+                               cond_resched();
+                               goto again;
+                       }
                        if (!ret) {
                                btrfs_set_path_blocking(path);
                                btrfs_tree_read_lock(next);
index 7b845ff4af99fb643bd959e52dd6f202b7dee7ef..2936ca49b3b4af3a799f7585b74038d289ab8278 100644 (file)
@@ -2354,12 +2354,17 @@ retry_root_backup:
                                  BTRFS_CSUM_TREE_OBJECTID, csum_root);
        if (ret)
                goto recovery_tree_root;
-
        csum_root->track_dirty = 1;
 
        fs_info->generation = generation;
        fs_info->last_trans_committed = generation;
 
+       ret = btrfs_recover_balance(fs_info);
+       if (ret) {
+               printk(KERN_WARNING "btrfs: failed to recover balance\n");
+               goto fail_block_groups;
+       }
+
        ret = btrfs_init_dev_stats(fs_info);
        if (ret) {
                printk(KERN_ERR "btrfs: failed to init dev_stats: %d\n",
@@ -2485,20 +2490,23 @@ retry_root_backup:
                goto fail_trans_kthread;
        }
 
-       if (!(sb->s_flags & MS_RDONLY)) {
-               down_read(&fs_info->cleanup_work_sem);
-               err = btrfs_orphan_cleanup(fs_info->fs_root);
-               if (!err)
-                       err = btrfs_orphan_cleanup(fs_info->tree_root);
-               up_read(&fs_info->cleanup_work_sem);
+       if (sb->s_flags & MS_RDONLY)
+               return 0;
 
-               if (!err)
-                       err = btrfs_recover_balance(fs_info->tree_root);
+       down_read(&fs_info->cleanup_work_sem);
+       if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) ||
+           (ret = btrfs_orphan_cleanup(fs_info->tree_root))) {
+               up_read(&fs_info->cleanup_work_sem);
+               close_ctree(tree_root);
+               return ret;
+       }
+       up_read(&fs_info->cleanup_work_sem);
 
-               if (err) {
-                       close_ctree(tree_root);
-                       return err;
-               }
+       ret = btrfs_resume_balance_async(fs_info);
+       if (ret) {
+               printk(KERN_WARNING "btrfs: failed to resume balance\n");
+               close_ctree(tree_root);
+               return ret;
        }
 
        return 0;
index 4b5a1e1bdefbe095c239b464e55c9699e865175b..6e1d36702ff71c4fc5bde2733cbf166376b726d3 100644 (file)
@@ -2347,12 +2347,10 @@ next:
        return count;
 }
 
-
 static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs,
-                       unsigned long num_refs)
+                              unsigned long num_refs,
+                              struct list_head *first_seq)
 {
-       struct list_head *first_seq = delayed_refs->seq_head.next;
-
        spin_unlock(&delayed_refs->lock);
        pr_debug("waiting for more refs (num %ld, first %p)\n",
                 num_refs, first_seq);
@@ -2381,6 +2379,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
        struct btrfs_delayed_ref_root *delayed_refs;
        struct btrfs_delayed_ref_node *ref;
        struct list_head cluster;
+       struct list_head *first_seq = NULL;
        int ret;
        u64 delayed_start;
        int run_all = count == (unsigned long)-1;
@@ -2436,8 +2435,10 @@ again:
                                 */
                                consider_waiting = 1;
                                num_refs = delayed_refs->num_entries;
+                               first_seq = root->fs_info->tree_mod_seq_list.next;
                        } else {
-                               wait_for_more_refs(delayed_refs, num_refs);
+                               wait_for_more_refs(delayed_refs,
+                                                  num_refs, first_seq);
                                /*
                                 * after waiting, things have changed. we
                                 * dropped the lock and someone else might have
index aaa12c1eb3483a8371df48e5765b986c436451c4..01c21b6c6d43e44a28a4c862ca6532d6f8b02654 100644 (file)
@@ -3324,6 +3324,7 @@ static int extent_write_cache_pages(struct extent_io_tree *tree,
                             writepage_t writepage, void *data,
                             void (*flush_fn)(void *))
 {
+       struct inode *inode = mapping->host;
        int ret = 0;
        int done = 0;
        int nr_to_write_done = 0;
@@ -3334,6 +3335,18 @@ static int extent_write_cache_pages(struct extent_io_tree *tree,
        int scanned = 0;
        int tag;
 
+       /*
+        * We have to hold onto the inode so that ordered extents can do their
+        * work when the IO finishes.  The alternative to this is failing to add
+        * an ordered extent if the igrab() fails there and that is a huge pain
+        * to deal with, so instead just hold onto the inode throughout the
+        * writepages operation.  If it fails here we are freeing up the inode
+        * anyway and we'd rather not waste our time writing out stuff that is
+        * going to be truncated anyway.
+        */
+       if (!igrab(inode))
+               return 0;
+
        pagevec_init(&pvec, 0);
        if (wbc->range_cyclic) {
                index = mapping->writeback_index; /* Start from prev offset */
@@ -3428,6 +3441,7 @@ retry:
                index = 0;
                goto retry;
        }
+       btrfs_add_delayed_iput(inode);
        return ret;
 }
 
index 70dc8ca73e257bc3a1e7a96ea48009bff093af9a..9aa01ec2138d466f3d1726ccd6291d054c5e5c98 100644 (file)
@@ -1334,7 +1334,6 @@ static ssize_t __btrfs_direct_write(struct kiocb *iocb,
                                    loff_t *ppos, size_t count, size_t ocount)
 {
        struct file *file = iocb->ki_filp;
-       struct inode *inode = fdentry(file)->d_inode;
        struct iov_iter i;
        ssize_t written;
        ssize_t written_buffered;
@@ -1344,18 +1343,6 @@ static ssize_t __btrfs_direct_write(struct kiocb *iocb,
        written = generic_file_direct_write(iocb, iov, &nr_segs, pos, ppos,
                                            count, ocount);
 
-       /*
-        * the generic O_DIRECT will update in-memory i_size after the
-        * DIOs are done.  But our endio handlers that update the on
-        * disk i_size never update past the in memory i_size.  So we
-        * need one more update here to catch any additions to the
-        * file
-        */
-       if (inode->i_size != BTRFS_I(inode)->disk_i_size) {
-               btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
-               mark_inode_dirty(inode);
-       }
-
        if (written < 0 || written == count)
                return written;
 
index 81296c57405a5d53a27dba626a4d6201829bd578..6c4e2baa9290e16d06a4a8dfc5c3b05880cfeb27 100644 (file)
@@ -1543,29 +1543,26 @@ again:
        end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * ctl->unit) - 1;
 
        /*
-        * XXX - this can go away after a few releases.
-        *
-        * since the only user of btrfs_remove_free_space is the tree logging
-        * stuff, and the only way to test that is under crash conditions, we
-        * want to have this debug stuff here just in case somethings not
-        * working.  Search the bitmap for the space we are trying to use to
-        * make sure its actually there.  If its not there then we need to stop
-        * because something has gone wrong.
+        * We need to search for bits in this bitmap.  We could only cover some
+        * of the extent in this bitmap thanks to how we add space, so we need
+        * to search for as much as it as we can and clear that amount, and then
+        * go searching for the next bit.
         */
        search_start = *offset;
-       search_bytes = *bytes;
+       search_bytes = ctl->unit;
        search_bytes = min(search_bytes, end - search_start + 1);
        ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes);
        BUG_ON(ret < 0 || search_start != *offset);
 
-       if (*offset > bitmap_info->offset && *offset + *bytes > end) {
-               bitmap_clear_bits(ctl, bitmap_info, *offset, end - *offset + 1);
-               *bytes -= end - *offset + 1;
-               *offset = end + 1;
-       } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) {
-               bitmap_clear_bits(ctl, bitmap_info, *offset, *bytes);
-               *bytes = 0;
-       }
+       /* We may have found more bits than what we need */
+       search_bytes = min(search_bytes, *bytes);
+
+       /* Cannot clear past the end of the bitmap */
+       search_bytes = min(search_bytes, end - search_start + 1);
+
+       bitmap_clear_bits(ctl, bitmap_info, search_start, search_bytes);
+       *offset += search_bytes;
+       *bytes -= search_bytes;
 
        if (*bytes) {
                struct rb_node *next = rb_next(&bitmap_info->offset_index);
@@ -1596,7 +1593,7 @@ again:
                 * everything over again.
                 */
                search_start = *offset;
-               search_bytes = *bytes;
+               search_bytes = ctl->unit;
                ret = search_bitmap(ctl, bitmap_info, &search_start,
                                    &search_bytes);
                if (ret < 0 || search_start != *offset)
@@ -1879,12 +1876,14 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *info;
-       struct btrfs_free_space *next_info = NULL;
        int ret = 0;
 
        spin_lock(&ctl->tree_lock);
 
 again:
+       if (!bytes)
+               goto out_lock;
+
        info = tree_search_offset(ctl, offset, 0, 0);
        if (!info) {
                /*
@@ -1905,88 +1904,48 @@ again:
                }
        }
 
-       if (info->bytes < bytes && rb_next(&info->offset_index)) {
-               u64 end;
-               next_info = rb_entry(rb_next(&info->offset_index),
-                                            struct btrfs_free_space,
-                                            offset_index);
-
-               if (next_info->bitmap)
-                       end = next_info->offset +
-                             BITS_PER_BITMAP * ctl->unit - 1;
-               else
-                       end = next_info->offset + next_info->bytes;
-
-               if (next_info->bytes < bytes ||
-                   next_info->offset > offset || offset > end) {
-                       printk(KERN_CRIT "Found free space at %llu, size %llu,"
-                             " trying to use %llu\n",
-                             (unsigned long long)info->offset,
-                             (unsigned long long)info->bytes,
-                             (unsigned long long)bytes);
-                       WARN_ON(1);
-                       ret = -EINVAL;
-                       goto out_lock;
-               }
-
-               info = next_info;
-       }
-
-       if (info->bytes == bytes) {
+       if (!info->bitmap) {
                unlink_free_space(ctl, info);
-               if (info->bitmap) {
-                       kfree(info->bitmap);
-                       ctl->total_bitmaps--;
-               }
-               kmem_cache_free(btrfs_free_space_cachep, info);
-               ret = 0;
-               goto out_lock;
-       }
-
-       if (!info->bitmap && info->offset == offset) {
-               unlink_free_space(ctl, info);
-               info->offset += bytes;
-               info->bytes -= bytes;
-               ret = link_free_space(ctl, info);
-               WARN_ON(ret);
-               goto out_lock;
-       }
+               if (offset == info->offset) {
+                       u64 to_free = min(bytes, info->bytes);
+
+                       info->bytes -= to_free;
+                       info->offset += to_free;
+                       if (info->bytes) {
+                               ret = link_free_space(ctl, info);
+                               WARN_ON(ret);
+                       } else {
+                               kmem_cache_free(btrfs_free_space_cachep, info);
+                       }
 
-       if (!info->bitmap && info->offset <= offset &&
-           info->offset + info->bytes >= offset + bytes) {
-               u64 old_start = info->offset;
-               /*
-                * we're freeing space in the middle of the info,
-                * this can happen during tree log replay
-                *
-                * first unlink the old info and then
-                * insert it again after the hole we're creating
-                */
-               unlink_free_space(ctl, info);
-               if (offset + bytes < info->offset + info->bytes) {
-                       u64 old_end = info->offset + info->bytes;
+                       offset += to_free;
+                       bytes -= to_free;
+                       goto again;
+               } else {
+                       u64 old_end = info->bytes + info->offset;
 
-                       info->offset = offset + bytes;
-                       info->bytes = old_end - info->offset;
+                       info->bytes = offset - info->offset;
                        ret = link_free_space(ctl, info);
                        WARN_ON(ret);
                        if (ret)
                                goto out_lock;
-               } else {
-                       /* the hole we're creating ends at the end
-                        * of the info struct, just free the info
-                        */
-                       kmem_cache_free(btrfs_free_space_cachep, info);
-               }
-               spin_unlock(&ctl->tree_lock);
 
-               /* step two, insert a new info struct to cover
-                * anything before the hole
-                */
-               ret = btrfs_add_free_space(block_group, old_start,
-                                          offset - old_start);
-               WARN_ON(ret); /* -ENOMEM */
-               goto out;
+                       /* Not enough bytes in this entry to satisfy us */
+                       if (old_end < offset + bytes) {
+                               bytes -= old_end - offset;
+                               offset = old_end;
+                               goto again;
+                       } else if (old_end == offset + bytes) {
+                               /* all done */
+                               goto out_lock;
+                       }
+                       spin_unlock(&ctl->tree_lock);
+
+                       ret = btrfs_add_free_space(block_group, offset + bytes,
+                                                  old_end - (offset + bytes));
+                       WARN_ON(ret);
+                       goto out;
+               }
        }
 
        ret = remove_from_bitmap(ctl, info, &offset, &bytes);
index d8bb0dbc4941ca3f288119134df64eeb1eb679da..fb8d671d00e6b8c7d8b387d4f158f8ab46d362f1 100644 (file)
@@ -3754,7 +3754,7 @@ void btrfs_evict_inode(struct inode *inode)
        btrfs_wait_ordered_range(inode, 0, (u64)-1);
 
        if (root->fs_info->log_root_recovering) {
-               BUG_ON(!test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
+               BUG_ON(test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                                 &BTRFS_I(inode)->runtime_flags));
                goto no_delete;
        }
@@ -4247,7 +4247,7 @@ static void btrfs_dentry_release(struct dentry *dentry)
 }
 
 static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        struct dentry *ret;
 
@@ -4893,7 +4893,7 @@ out_unlock:
 }
 
 static int btrfs_create(struct inode *dir, struct dentry *dentry,
-                       umode_t mode, struct nameidata *nd)
+                       umode_t mode, bool excl)
 {
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
@@ -5876,8 +5876,17 @@ map:
        bh_result->b_size = len;
        bh_result->b_bdev = em->bdev;
        set_buffer_mapped(bh_result);
-       if (create && !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
-               set_buffer_new(bh_result);
+       if (create) {
+               if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
+                       set_buffer_new(bh_result);
+
+               /*
+                * Need to update the i_size under the extent lock so buffered
+                * readers will get the updated i_size when we unlock.
+                */
+               if (start + len > i_size_read(inode))
+                       i_size_write(inode, start + len);
+       }
 
        free_extent_map(em);
 
@@ -6360,12 +6369,48 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                 */
                ordered = btrfs_lookup_ordered_range(inode, lockstart,
                                                     lockend - lockstart + 1);
-               if (!ordered)
+
+               /*
+                * We need to make sure there are no buffered pages in this
+                * range either, we could have raced between the invalidate in
+                * generic_file_direct_write and locking the extent.  The
+                * invalidate needs to happen so that reads after a write do not
+                * get stale data.
+                */
+               if (!ordered && (!writing ||
+                   !test_range_bit(&BTRFS_I(inode)->io_tree,
+                                   lockstart, lockend, EXTENT_UPTODATE, 0,
+                                   cached_state)))
                        break;
+
                unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
                                     &cached_state, GFP_NOFS);
-               btrfs_start_ordered_extent(inode, ordered, 1);
-               btrfs_put_ordered_extent(ordered);
+
+               if (ordered) {
+                       btrfs_start_ordered_extent(inode, ordered, 1);
+                       btrfs_put_ordered_extent(ordered);
+               } else {
+                       /* Screw you mmap */
+                       ret = filemap_write_and_wait_range(file->f_mapping,
+                                                          lockstart,
+                                                          lockend);
+                       if (ret)
+                               goto out;
+
+                       /*
+                        * If we found a page that couldn't be invalidated just
+                        * fall back to buffered.
+                        */
+                       ret = invalidate_inode_pages2_range(file->f_mapping,
+                                       lockstart >> PAGE_CACHE_SHIFT,
+                                       lockend >> PAGE_CACHE_SHIFT);
+                       if (ret) {
+                               if (ret == -EBUSY)
+                                       ret = 0;
+                               goto out;
+                       }
+               }
+
                cond_resched();
        }
 
@@ -6942,7 +6987,7 @@ void btrfs_destroy_inode(struct inode *inode)
        struct btrfs_ordered_extent *ordered;
        struct btrfs_root *root = BTRFS_I(inode)->root;
 
-       WARN_ON(!list_empty(&inode->i_dentry));
+       WARN_ON(!hlist_empty(&inode->i_dentry));
        WARN_ON(inode->i_data.nrpages);
        WARN_ON(BTRFS_I(inode)->outstanding_extents);
        WARN_ON(BTRFS_I(inode)->reserved_extents);
index 0e92e5763005214b5d55d091d6fcfb94d73f4875..1e9f6c019ad069ea51a5bc7ea475fd0d804dc1ae 100644 (file)
@@ -3268,7 +3268,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
        if (fs_info->sb->s_flags & MS_RDONLY)
                return -EROFS;
 
-       ret = mnt_want_write(file->f_path.mnt);
+       ret = mnt_want_write_file(file);
        if (ret)
                return ret;
 
@@ -3338,7 +3338,7 @@ out_bargs:
 out:
        mutex_unlock(&fs_info->balance_mutex);
        mutex_unlock(&fs_info->volume_mutex);
-       mnt_drop_write(file->f_path.mnt);
+       mnt_drop_write_file(file);
        return ret;
 }
 
index 497c530724cf6b7a50296d2c6660fef7f4066cb9..e440aa653c30d6f6c8ad1e7437bfa6e2b4d50799 100644 (file)
@@ -339,7 +339,7 @@ struct btrfs_ioctl_get_dev_stats {
 #define BTRFS_IOC_WAIT_SYNC  _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
 #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
                                   struct btrfs_ioctl_vol_args_v2)
-#define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64)
+#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)
 #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
 #define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \
                              struct btrfs_ioctl_scrub_args)
index 0eb9a4da069e6cb1e3c4294d4ad02e2ab92da666..b19d7556772877acac123d6d0ff94080a1cab69b 100644 (file)
@@ -1068,7 +1068,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        }
 
        bdev = fs_devices->latest_bdev;
-       s = sget(fs_type, btrfs_test_super, btrfs_set_super, fs_info);
+       s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | MS_NOSEC,
+                fs_info);
        if (IS_ERR(s)) {
                error = PTR_ERR(s);
                goto error_close_devices;
@@ -1082,7 +1083,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
        } else {
                char b[BDEVNAME_SIZE];
 
-               s->s_flags = flags | MS_NOSEC;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                btrfs_sb(s)->bdev_holder = fs_type;
                error = btrfs_fill_super(s, fs_devices, data,
@@ -1187,6 +1187,10 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                if (ret)
                        goto restore;
 
+               ret = btrfs_resume_balance_async(fs_info);
+               if (ret)
+                       goto restore;
+
                sb->s_flags &= ~MS_RDONLY;
        }
 
index 2017d0ff511ca3304dad46e85045ad2ab28d4e75..8abeae4224f92dbd870877b76224515c304e979d 100644 (file)
@@ -690,6 +690,8 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
        kfree(name);
 
        iput(inode);
+
+       btrfs_run_delayed_items(trans, root);
        return ret;
 }
 
@@ -895,6 +897,7 @@ again:
                                ret = btrfs_unlink_inode(trans, root, dir,
                                                         inode, victim_name,
                                                         victim_name_len);
+                               btrfs_run_delayed_items(trans, root);
                        }
                        kfree(victim_name);
                        ptr = (unsigned long)(victim_ref + 1) + victim_name_len;
@@ -1475,6 +1478,9 @@ again:
                        ret = btrfs_unlink_inode(trans, root, dir, inode,
                                                 name, name_len);
                        BUG_ON(ret);
+
+                       btrfs_run_delayed_items(trans, root);
+
                        kfree(name);
                        iput(inode);
 
index 8a3d2594b80726b3a4da08c5924cb51b8e28a0ba..ecaad40e7ef499fedb7667659d9efd955a661eaa 100644 (file)
@@ -2845,31 +2845,48 @@ out:
 
 static int balance_kthread(void *data)
 {
-       struct btrfs_balance_control *bctl =
-                       (struct btrfs_balance_control *)data;
-       struct btrfs_fs_info *fs_info = bctl->fs_info;
+       struct btrfs_fs_info *fs_info = data;
        int ret = 0;
 
        mutex_lock(&fs_info->volume_mutex);
        mutex_lock(&fs_info->balance_mutex);
 
-       set_balance_control(bctl);
-
-       if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
-               printk(KERN_INFO "btrfs: force skipping balance\n");
-       } else {
+       if (fs_info->balance_ctl) {
                printk(KERN_INFO "btrfs: continuing balance\n");
-               ret = btrfs_balance(bctl, NULL);
+               ret = btrfs_balance(fs_info->balance_ctl, NULL);
        }
 
        mutex_unlock(&fs_info->balance_mutex);
        mutex_unlock(&fs_info->volume_mutex);
+
        return ret;
 }
 
-int btrfs_recover_balance(struct btrfs_root *tree_root)
+int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
 {
        struct task_struct *tsk;
+
+       spin_lock(&fs_info->balance_lock);
+       if (!fs_info->balance_ctl) {
+               spin_unlock(&fs_info->balance_lock);
+               return 0;
+       }
+       spin_unlock(&fs_info->balance_lock);
+
+       if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
+               printk(KERN_INFO "btrfs: force skipping balance\n");
+               return 0;
+       }
+
+       tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance");
+       if (IS_ERR(tsk))
+               return PTR_ERR(tsk);
+
+       return 0;
+}
+
+int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
+{
        struct btrfs_balance_control *bctl;
        struct btrfs_balance_item *item;
        struct btrfs_disk_balance_args disk_bargs;
@@ -2882,29 +2899,30 @@ int btrfs_recover_balance(struct btrfs_root *tree_root)
        if (!path)
                return -ENOMEM;
 
-       bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
-       if (!bctl) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
        key.objectid = BTRFS_BALANCE_OBJECTID;
        key.type = BTRFS_BALANCE_ITEM_KEY;
        key.offset = 0;
 
-       ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
+       ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0);
        if (ret < 0)
-               goto out_bctl;
+               goto out;
        if (ret > 0) { /* ret = -ENOENT; */
                ret = 0;
-               goto out_bctl;
+               goto out;
+       }
+
+       bctl = kzalloc(sizeof(*bctl), GFP_NOFS);
+       if (!bctl) {
+               ret = -ENOMEM;
+               goto out;
        }
 
        leaf = path->nodes[0];
        item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item);
 
-       bctl->fs_info = tree_root->fs_info;
-       bctl->flags = btrfs_balance_flags(leaf, item) | BTRFS_BALANCE_RESUME;
+       bctl->fs_info = fs_info;
+       bctl->flags = btrfs_balance_flags(leaf, item);
+       bctl->flags |= BTRFS_BALANCE_RESUME;
 
        btrfs_balance_data(leaf, item, &disk_bargs);
        btrfs_disk_balance_args_to_cpu(&bctl->data, &disk_bargs);
@@ -2913,14 +2931,13 @@ int btrfs_recover_balance(struct btrfs_root *tree_root)
        btrfs_balance_sys(leaf, item, &disk_bargs);
        btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs);
 
-       tsk = kthread_run(balance_kthread, bctl, "btrfs-balance");
-       if (IS_ERR(tsk))
-               ret = PTR_ERR(tsk);
-       else
-               goto out;
+       mutex_lock(&fs_info->volume_mutex);
+       mutex_lock(&fs_info->balance_mutex);
 
-out_bctl:
-       kfree(bctl);
+       set_balance_control(bctl);
+
+       mutex_unlock(&fs_info->balance_mutex);
+       mutex_unlock(&fs_info->volume_mutex);
 out:
        btrfs_free_path(path);
        return ret;
@@ -4061,16 +4078,18 @@ static void btrfs_end_bio(struct bio *bio, int err)
 
                        BUG_ON(stripe_index >= bbio->num_stripes);
                        dev = bbio->stripes[stripe_index].dev;
-                       if (bio->bi_rw & WRITE)
-                               btrfs_dev_stat_inc(dev,
-                                                  BTRFS_DEV_STAT_WRITE_ERRS);
-                       else
-                               btrfs_dev_stat_inc(dev,
-                                                  BTRFS_DEV_STAT_READ_ERRS);
-                       if ((bio->bi_rw & WRITE_FLUSH) == WRITE_FLUSH)
-                               btrfs_dev_stat_inc(dev,
-                                                  BTRFS_DEV_STAT_FLUSH_ERRS);
-                       btrfs_dev_stat_print_on_error(dev);
+                       if (dev->bdev) {
+                               if (bio->bi_rw & WRITE)
+                                       btrfs_dev_stat_inc(dev,
+                                               BTRFS_DEV_STAT_WRITE_ERRS);
+                               else
+                                       btrfs_dev_stat_inc(dev,
+                                               BTRFS_DEV_STAT_READ_ERRS);
+                               if ((bio->bi_rw & WRITE_FLUSH) == WRITE_FLUSH)
+                                       btrfs_dev_stat_inc(dev,
+                                               BTRFS_DEV_STAT_FLUSH_ERRS);
+                               btrfs_dev_stat_print_on_error(dev);
+                       }
                }
        }
 
index 74366f27a76bbc7272e4b41f2f92bf9520bca813..95f6637614db5932f8d52daba79943514a7ed8da 100644 (file)
@@ -281,7 +281,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_balance(struct btrfs_balance_control *bctl,
                  struct btrfs_ioctl_balance_args *bargs);
-int btrfs_recover_balance(struct btrfs_root *tree_root);
+int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
+int btrfs_recover_balance(struct btrfs_fs_info *fs_info);
 int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
 int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
index 838a9cf246bd0fa561ab66295f9bb3df77e0c6a2..c7062c896d7c20489f41ea838640a5cfa5387ca9 100644 (file)
@@ -1036,6 +1036,9 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
 static struct buffer_head *
 __getblk_slow(struct block_device *bdev, sector_t block, int size)
 {
+       int ret;
+       struct buffer_head *bh;
+
        /* Size must be multiple of hard sectorsize */
        if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
                        (size < 512 || size > PAGE_SIZE))) {
@@ -1048,20 +1051,21 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
                return NULL;
        }
 
-       for (;;) {
-               struct buffer_head * bh;
-               int ret;
+retry:
+       bh = __find_get_block(bdev, block, size);
+       if (bh)
+               return bh;
 
+       ret = grow_buffers(bdev, block, size);
+       if (ret == 0) {
+               free_more_memory();
+               goto retry;
+       } else if (ret > 0) {
                bh = __find_get_block(bdev, block, size);
                if (bh)
                        return bh;
-
-               ret = grow_buffers(bdev, block, size);
-               if (ret < 0)
-                       return NULL;
-               if (ret == 0)
-                       free_more_memory();
        }
+       return NULL;
 }
 
 /*
index 7f0771d3894e7a17bbd01ec1bf9fc8c988918d08..b0b5f7cdfffa98de3e30e0857d64bf954e8b3518 100644 (file)
@@ -567,7 +567,7 @@ lookup_again:
                        if (ret < 0)
                                goto create_error;
                        start = jiffies;
-                       ret = vfs_create(dir->d_inode, next, S_IFREG, NULL);
+                       ret = vfs_create(dir->d_inode, next, S_IFREG, true);
                        cachefiles_hist(cachefiles_create_histogram, start);
                        if (ret < 0)
                                goto create_error;
index 0e3c0924cc3a3f01f648731b1e3baed15a7ce1ad..c0353dfac51f819d3e8cb69644fd50a98fa04224 100644 (file)
@@ -891,6 +891,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
        struct cachefiles_cache *cache;
        mm_segment_t old_fs;
        struct file *file;
+       struct path path;
        loff_t pos, eof;
        size_t len;
        void *data;
@@ -916,10 +917,9 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
 
        /* write the page to the backing filesystem and let it store it in its
         * own time */
-       dget(object->backer);
-       mntget(cache->mnt);
-       file = dentry_open(object->backer, cache->mnt, O_RDWR,
-                          cache->cache_cred);
+       path.mnt = cache->mnt;
+       path.dentry = object->backer;
+       file = dentry_open(&path, O_RDWR, cache->cache_cred);
        if (IS_ERR(file)) {
                ret = PTR_ERR(file);
        } else {
index 3e8094be4604a481999e2921fb0942441c9086a7..00894ff9246c2175b60177bab59b70456733ff01 100644 (file)
@@ -576,7 +576,7 @@ static int is_root_ceph_dentry(struct inode *inode, struct dentry *dentry)
  * the MDS so that it gets our 'caps wanted' value in a single op.
  */
 static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
-                                 struct nameidata *nd)
+                                 unsigned int flags)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
@@ -594,14 +594,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
        if (err < 0)
                return ERR_PTR(err);
 
-       /* open (but not create!) intent? */
-       if (nd &&
-           (nd->flags & LOOKUP_OPEN) &&
-           !(nd->intent.open.flags & O_CREAT)) {
-               int mode = nd->intent.open.create_mode & ~current->fs->umask;
-               return ceph_lookup_open(dir, dentry, nd, mode, 1);
-       }
-
        /* can we conclude ENOENT locally? */
        if (dentry->d_inode == NULL) {
                struct ceph_inode_info *ci = ceph_inode(dir);
@@ -642,13 +634,51 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
        return dentry;
 }
 
+int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
+                    struct file *file, unsigned flags, umode_t mode,
+                    int *opened)
+{
+       int err;
+       struct dentry *res = NULL;
+
+       if (!(flags & O_CREAT)) {
+               if (dentry->d_name.len > NAME_MAX)
+                       return -ENAMETOOLONG;
+
+               err = ceph_init_dentry(dentry);
+               if (err < 0)
+                       return err;
+
+               return ceph_lookup_open(dir, dentry, file, flags, mode, opened);
+       }
+
+       if (d_unhashed(dentry)) {
+               res = ceph_lookup(dir, dentry, 0);
+               if (IS_ERR(res))
+                       return PTR_ERR(res);
+
+               if (res)
+                       dentry = res;
+       }
+
+       /* We don't deal with positive dentries here */
+       if (dentry->d_inode)
+               return finish_no_open(file, res);
+
+       *opened |= FILE_CREATED;
+       err = ceph_lookup_open(dir, dentry, file, flags, mode, opened);
+       dput(res);
+
+       return err;
+}
+
 /*
  * If we do a create but get no trace back from the MDS, follow up with
  * a lookup (the VFS expects us to link up the provided dentry).
  */
 int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
 {
-       struct dentry *result = ceph_lookup(dir, dentry, NULL);
+       struct dentry *result = ceph_lookup(dir, dentry, 0);
 
        if (result && !IS_ERR(result)) {
                /*
@@ -700,25 +730,9 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
 }
 
 static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                      struct nameidata *nd)
+                      bool excl)
 {
-       dout("create in dir %p dentry %p name '%.*s'\n",
-            dir, dentry, dentry->d_name.len, dentry->d_name.name);
-
-       if (ceph_snap(dir) != CEPH_NOSNAP)
-               return -EROFS;
-
-       if (nd) {
-               BUG_ON((nd->flags & LOOKUP_OPEN) == 0);
-               dentry = ceph_lookup_open(dir, dentry, nd, mode, 0);
-               /* hrm, what should i do here if we get aliased? */
-               if (IS_ERR(dentry))
-                       return PTR_ERR(dentry);
-               return 0;
-       }
-
-       /* fall back to mknod */
-       return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0);
+       return ceph_mknod(dir, dentry, mode, 0);
 }
 
 static int ceph_symlink(struct inode *dir, struct dentry *dentry,
@@ -1028,12 +1042,12 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
 /*
  * Check if cached dentry can be trusted.
  */
-static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        int valid = 0;
        struct inode *dir;
 
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
@@ -1080,7 +1094,7 @@ static void ceph_d_release(struct dentry *dentry)
 }
 
 static int ceph_snapdir_d_revalidate(struct dentry *dentry,
-                                         struct nameidata *nd)
+                                         unsigned int flags)
 {
        /*
         * Eventually, we'll want to revalidate snapped metadata
@@ -1357,6 +1371,7 @@ const struct inode_operations ceph_dir_iops = {
        .rmdir = ceph_unlink,
        .rename = ceph_rename,
        .create = ceph_create,
+       .atomic_open = ceph_atomic_open,
 };
 
 const struct dentry_operations ceph_dentry_ops = {
index 988d4f302e4880281a2b5e04c9f44dd7870202d2..1b81d6c318784813973bc74cccfec02fed0d3dbc 100644 (file)
@@ -213,22 +213,15 @@ out:
  * may_open() fails, the struct *file gets cleaned up (i.e.
  * ceph_release gets called).  So fear not!
  */
-/*
- * flags
- *  path_lookup_open   -> LOOKUP_OPEN
- *  path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE
- */
-struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
-                               struct nameidata *nd, int mode,
-                               int locked_dir)
+int ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+                    struct file *file, unsigned flags, umode_t mode,
+                    int *opened)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
-       struct file *file;
        struct ceph_mds_request *req;
        struct dentry *ret;
        int err;
-       int flags = nd->intent.open.flags;
 
        dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n",
             dentry, dentry->d_name.len, dentry->d_name.name, flags, mode);
@@ -236,7 +229,7 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
        /* do the open */
        req = prepare_open_request(dir->i_sb, flags, mode);
        if (IS_ERR(req))
-               return ERR_CAST(req);
+               return PTR_ERR(req);
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
        if (flags & O_CREAT) {
@@ -254,14 +247,17 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
                err = ceph_handle_notrace_create(dir, dentry);
        if (err)
                goto out;
-       file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open);
-       if (IS_ERR(file))
-               err = PTR_ERR(file);
+       err = finish_open(file, req->r_dentry, ceph_open, opened);
 out:
        ret = ceph_finish_lookup(req, dentry, err);
        ceph_mdsc_put_request(req);
        dout("ceph_lookup_open result=%p\n", ret);
-       return ret;
+
+       if (IS_ERR(ret))
+               return PTR_ERR(ret);
+
+       dput(ret);
+       return err;
 }
 
 int ceph_release(struct inode *inode, struct file *file)
index 1e67dd7305a4e8596a3c5f609ccea2a866e4e31a..7076109f014dae80a85c789c3022b6465f9b70c0 100644 (file)
@@ -871,7 +871,7 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
 
        if (ceph_test_opt(fsc->client, NOSHARE))
                compare_super = NULL;
-       sb = sget(fs_type, compare_super, ceph_set_super, fsc);
+       sb = sget(fs_type, compare_super, ceph_set_super, flags, fsc);
        if (IS_ERR(sb)) {
                res = ERR_CAST(sb);
                goto out;
index fc35036d258d7b830c37f5cba078f53c53e7d574..f4d5522cb619eba5f5a27842ea52277e9b3d5563 100644 (file)
@@ -806,9 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages,
                                    loff_t off, size_t len);
 extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
 extern int ceph_open(struct inode *inode, struct file *file);
-extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
-                                      struct nameidata *nd, int mode,
-                                      int locked_dir);
+extern int ceph_lookup_open(struct inode *dir, struct dentry *dentry,
+                            struct file *od, unsigned flags,
+                            umode_t mode, int *opened);
 extern int ceph_release(struct inode *inode, struct file *filp);
 
 /* dir.c */
index 8b6e344eb0ba3a483780f0b32cf0961ec258ca4c..a7610cfedf0a20c7c3d22d149d129d1b15e62bd3 100644 (file)
@@ -257,7 +257,6 @@ cifs_alloc_inode(struct super_block *sb)
 static void cifs_i_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
-       INIT_LIST_HEAD(&inode->i_dentry);
        kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
 }
 
@@ -638,7 +637,10 @@ cifs_do_mount(struct file_system_type *fs_type,
        mnt_data.cifs_sb = cifs_sb;
        mnt_data.flags = flags;
 
-       sb = sget(fs_type, cifs_match_super, cifs_set_super, &mnt_data);
+       /* BB should we make this contingent on mount parm? */
+       flags |= MS_NODIRATIME | MS_NOATIME;
+
+       sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data);
        if (IS_ERR(sb)) {
                root = ERR_CAST(sb);
                cifs_umount(cifs_sb);
@@ -649,10 +651,6 @@ cifs_do_mount(struct file_system_type *fs_type,
                cFYI(1, "Use existing superblock");
                cifs_umount(cifs_sb);
        } else {
-               sb->s_flags = flags;
-               /* BB should we make this contingent on mount parm? */
-               sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
-
                rc = cifs_read_super(sb);
                if (rc) {
                        root = ERR_PTR(rc);
@@ -778,6 +776,7 @@ struct file_system_type cifs_fs_type = {
 };
 const struct inode_operations cifs_dir_inode_ops = {
        .create = cifs_create,
+       .atomic_open = cifs_atomic_open,
        .lookup = cifs_lookup,
        .getattr = cifs_getattr,
        .unlink = cifs_unlink,
index 65365358c9766dcd2882ab643805565e552f4e25..1c49c5a9b27a6cd5b188425dfdd3fd934687a003 100644 (file)
@@ -45,9 +45,12 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf;
 extern const struct inode_operations cifs_dir_inode_ops;
 extern struct inode *cifs_root_iget(struct super_block *);
 extern int cifs_create(struct inode *, struct dentry *, umode_t,
-                      struct nameidata *);
+                      bool excl);
+extern int cifs_atomic_open(struct inode *, struct dentry *,
+                           struct file *, unsigned, umode_t,
+                           int *);
 extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
-                                 struct nameidata *);
+                                 unsigned int);
 extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
 extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
 extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
index 5b400730c213d518deec2086b1513bbac7fd2a4d..4ee522b3f66f0036737a688b0c97606ee1efe2ce 100644 (file)
@@ -86,7 +86,31 @@ static struct {
 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
 #endif /* CIFS_POSIX */
 
-/* Forward declarations */
+#ifdef CONFIG_HIGHMEM
+/*
+ * On arches that have high memory, kmap address space is limited. By
+ * serializing the kmap operations on those arches, we ensure that we don't
+ * end up with a bunch of threads in writeback with partially mapped page
+ * arrays, stuck waiting for kmap to come back. That situation prevents
+ * progress and can deadlock.
+ */
+static DEFINE_MUTEX(cifs_kmap_mutex);
+
+static inline void
+cifs_kmap_lock(void)
+{
+       mutex_lock(&cifs_kmap_mutex);
+}
+
+static inline void
+cifs_kmap_unlock(void)
+{
+       mutex_unlock(&cifs_kmap_mutex);
+}
+#else /* !CONFIG_HIGHMEM */
+#define cifs_kmap_lock() do { ; } while(0)
+#define cifs_kmap_unlock() do { ; } while(0)
+#endif /* CONFIG_HIGHMEM */
 
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
@@ -1503,7 +1527,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        }
 
        /* marshal up the page array */
+       cifs_kmap_lock();
        len = rdata->marshal_iov(rdata, data_len);
+       cifs_kmap_unlock();
        data_len -= len;
 
        /* issue the read if we have any iovecs left to fill */
@@ -2069,7 +2095,9 @@ cifs_async_writev(struct cifs_writedata *wdata)
         * and set the iov_len properly for each one. It may also set
         * wdata->bytes too.
         */
+       cifs_kmap_lock();
        wdata->marshal_iov(iov, wdata);
+       cifs_kmap_unlock();
 
        cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
 
index 78db68a5cf44c83ddc8f60cfa89e4796d8fa0ffc..94b7788c3189281e043ecf82b9bf4fb1e9d0e0f7 100644 (file)
@@ -1653,24 +1653,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                         * If yes, we have encountered a double deliminator
                         * reset the NULL character to the deliminator
                         */
-                       if (tmp_end < end && tmp_end[1] == delim)
+                       if (tmp_end < end && tmp_end[1] == delim) {
                                tmp_end[0] = delim;
 
-                       /* Keep iterating until we get to a single deliminator
-                        * OR the end
-                        */
-                       while ((tmp_end = strchr(tmp_end, delim)) != NULL &&
-                              (tmp_end[1] == delim)) {
-                               tmp_end = (char *) &tmp_end[2];
-                       }
+                               /* Keep iterating until we get to a single
+                                * deliminator OR the end
+                                */
+                               while ((tmp_end = strchr(tmp_end, delim))
+                                       != NULL && (tmp_end[1] == delim)) {
+                                               tmp_end = (char *) &tmp_end[2];
+                               }
 
-                       /* Reset var options to point to next element */
-                       if (tmp_end) {
-                               tmp_end[0] = '\0';
-                               options = (char *) &tmp_end[1];
-                       } else
-                               /* Reached the end of the mount option string */
-                               options = end;
+                               /* Reset var options to point to next element */
+                               if (tmp_end) {
+                                       tmp_end[0] = '\0';
+                                       options = (char *) &tmp_end[1];
+                               } else
+                                       /* Reached the end of the mount option
+                                        * string */
+                                       options = end;
+                       }
 
                        /* Now build new password string */
                        temp_len = strlen(value);
@@ -3443,6 +3445,18 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
 #define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
 #define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
 
+/*
+ * On hosts with high memory, we can't currently support wsize/rsize that are
+ * larger than we can kmap at once. Cap the rsize/wsize at
+ * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
+ * larger than that anyway.
+ */
+#ifdef CONFIG_HIGHMEM
+#define CIFS_KMAP_SIZE_LIMIT   (LAST_PKMAP * PAGE_CACHE_SIZE)
+#else /* CONFIG_HIGHMEM */
+#define CIFS_KMAP_SIZE_LIMIT   (1<<24)
+#endif /* CONFIG_HIGHMEM */
+
 static unsigned int
 cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
 {
@@ -3473,6 +3487,9 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
                wsize = min_t(unsigned int, wsize,
                                server->maxBuf - sizeof(WRITE_REQ) + 4);
 
+       /* limit to the amount that we can kmap at once */
+       wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
+
        /* hard limit of CIFS_MAX_WSIZE */
        wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
 
@@ -3493,18 +3510,15 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
         * MS-CIFS indicates that servers are only limited by the client's
         * bufsize for reads, testing against win98se shows that it throws
         * INVALID_PARAMETER errors if you try to request too large a read.
+        * OS/2 just sends back short reads.
         *
-        * If the server advertises a MaxBufferSize of less than one page,
-        * assume that it also can't satisfy reads larger than that either.
-        *
-        * FIXME: Is there a better heuristic for this?
+        * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
+        * it can't handle a read request larger than its MaxBufferSize either.
         */
        if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
                defsize = CIFS_DEFAULT_IOSIZE;
        else if (server->capabilities & CAP_LARGE_READ_X)
                defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
-       else if (server->maxBuf >= PAGE_CACHE_SIZE)
-               defsize = CIFSMaxBufSize;
        else
                defsize = server->maxBuf - sizeof(READ_RSP);
 
@@ -3517,6 +3531,9 @@ cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
        if (!(server->capabilities & CAP_LARGE_READ_X))
                rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
 
+       /* limit to the amount that we can kmap at once */
+       rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
+
        /* hard limit of CIFS_MAX_RSIZE */
        rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
 
index ec4e9a2a12f843edf9e8d2f60c8a32f58011ec4d..a180265a10b56b5d4e98c63ff64e298f8146431f 100644 (file)
@@ -133,108 +133,141 @@ cifs_bp_rename_retry:
        return full_path;
 }
 
+/*
+ * Don't allow the separator character in a path component.
+ * The VFS will not allow "/", but "\" is allowed by posix.
+ */
+static int
+check_name(struct dentry *direntry)
+{
+       struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
+       int i;
+
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
+               for (i = 0; i < direntry->d_name.len; i++) {
+                       if (direntry->d_name.name[i] == '\\') {
+                               cFYI(1, "Invalid file name");
+                               return -EINVAL;
+                       }
+               }
+       }
+       return 0;
+}
+
+
 /* Inode operations in similar order to how they appear in Linux file fs.h */
 
-int
-cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
-               struct nameidata *nd)
+static int cifs_do_create(struct inode *inode, struct dentry *direntry,
+                         int xid, struct tcon_link *tlink, unsigned oflags,
+                         umode_t mode, __u32 *oplock, __u16 *fileHandle,
+                         int *created)
 {
        int rc = -ENOENT;
-       int xid;
        int create_options = CREATE_NOT_DIR;
-       __u32 oplock = 0;
-       int oflags;
-       /*
-        * BB below access is probably too much for mknod to request
-        *    but we have to do query and setpathinfo so requesting
-        *    less could fail (unless we want to request getatr and setatr
-        *    permissions (only).  At least for POSIX we do not have to
-        *    request so much.
-        */
-       int desiredAccess = GENERIC_READ | GENERIC_WRITE;
-       __u16 fileHandle;
-       struct cifs_sb_info *cifs_sb;
-       struct tcon_link *tlink;
-       struct cifs_tcon *tcon;
+       int desiredAccess;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifs_tcon *tcon = tlink_tcon(tlink);
        char *full_path = NULL;
        FILE_ALL_INFO *buf = NULL;
        struct inode *newinode = NULL;
-       int disposition = FILE_OVERWRITE_IF;
-
-       xid = GetXid();
-
-       cifs_sb = CIFS_SB(inode->i_sb);
-       tlink = cifs_sb_tlink(cifs_sb);
-       if (IS_ERR(tlink)) {
-               FreeXid(xid);
-               return PTR_ERR(tlink);
-       }
-       tcon = tlink_tcon(tlink);
+       int disposition;
 
+       *oplock = 0;
        if (tcon->ses->server->oplocks)
-               oplock = REQ_OPLOCK;
-
-       if (nd)
-               oflags = nd->intent.open.file->f_flags;
-       else
-               oflags = O_RDONLY | O_CREAT;
+               *oplock = REQ_OPLOCK;
 
        full_path = build_path_from_dentry(direntry);
        if (full_path == NULL) {
                rc = -ENOMEM;
-               goto cifs_create_out;
+               goto out;
        }
 
        if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
+           !tcon->broken_posix_open &&
            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
                rc = cifs_posix_open(full_path, &newinode,
-                       inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
-               /* EIO could indicate that (posix open) operation is not
-                  supported, despite what server claimed in capability
-                  negotiation.  EREMOTE indicates DFS junction, which is not
-                  handled in posix open */
-
-               if (rc == 0) {
-                       if (newinode == NULL) /* query inode info */
+                       inode->i_sb, mode, oflags, oplock, fileHandle, xid);
+               switch (rc) {
+               case 0:
+                       if (newinode == NULL) {
+                               /* query inode info */
                                goto cifs_create_get_file_info;
-                       else /* success, no need to query */
-                               goto cifs_create_set_dentry;
-               } else if ((rc != -EIO) && (rc != -EREMOTE) &&
-                        (rc != -EOPNOTSUPP) && (rc != -EINVAL))
-                       goto cifs_create_out;
-               /* else fallthrough to retry, using older open call, this is
-                  case where server does not support this SMB level, and
-                  falsely claims capability (also get here for DFS case
-                  which should be rare for path not covered on files) */
-       }
+                       }
+
+                       if (!S_ISREG(newinode->i_mode)) {
+                               /*
+                                * The server may allow us to open things like
+                                * FIFOs, but the client isn't set up to deal
+                                * with that. If it's not a regular file, just
+                                * close it and proceed as if it were a normal
+                                * lookup.
+                                */
+                               CIFSSMBClose(xid, tcon, *fileHandle);
+                               goto cifs_create_get_file_info;
+                       }
+                       /* success, no need to query */
+                       goto cifs_create_set_dentry;
+
+               case -ENOENT:
+                       goto cifs_create_get_file_info;
+
+               case -EIO:
+               case -EINVAL:
+                       /*
+                        * EIO could indicate that (posix open) operation is not
+                        * supported, despite what server claimed in capability
+                        * negotiation.
+                        *
+                        * POSIX open in samba versions 3.3.1 and earlier could
+                        * incorrectly fail with invalid parameter.
+                        */
+                       tcon->broken_posix_open = true;
+                       break;
+
+               case -EREMOTE:
+               case -EOPNOTSUPP:
+                       /*
+                        * EREMOTE indicates DFS junction, which is not handled
+                        * in posix open.  If either that or op not supported
+                        * returned, follow the normal lookup.
+                        */
+                       break;
 
-       if (nd) {
-               /* if the file is going to stay open, then we
-                  need to set the desired access properly */
-               desiredAccess = 0;
-               if (OPEN_FMODE(oflags) & FMODE_READ)
-                       desiredAccess |= GENERIC_READ; /* is this too little? */
-               if (OPEN_FMODE(oflags) & FMODE_WRITE)
-                       desiredAccess |= GENERIC_WRITE;
-
-               if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
-                       disposition = FILE_CREATE;
-               else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
-                       disposition = FILE_OVERWRITE_IF;
-               else if ((oflags & O_CREAT) == O_CREAT)
-                       disposition = FILE_OPEN_IF;
-               else
-                       cFYI(1, "Create flag not set in create function");
+               default:
+                       goto out;
+               }
+               /*
+                * fallthrough to retry, using older open call, this is case
+                * where server does not support this SMB level, and falsely
+                * claims capability (also get here for DFS case which should be
+                * rare for path not covered on files)
+                */
        }
 
+       desiredAccess = 0;
+       if (OPEN_FMODE(oflags) & FMODE_READ)
+               desiredAccess |= GENERIC_READ; /* is this too little? */
+       if (OPEN_FMODE(oflags) & FMODE_WRITE)
+               desiredAccess |= GENERIC_WRITE;
+
+       disposition = FILE_OVERWRITE_IF;
+       if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+               disposition = FILE_CREATE;
+       else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+               disposition = FILE_OVERWRITE_IF;
+       else if ((oflags & O_CREAT) == O_CREAT)
+               disposition = FILE_OPEN_IF;
+       else
+               cFYI(1, "Create flag not set in create function");
+
        /* BB add processing to set equivalent of mode - e.g. via CreateX with
           ACLs */
 
        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
        if (buf == NULL) {
                rc = -ENOMEM;
-               goto cifs_create_out;
+               goto out;
        }
 
        /*
@@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
        if (tcon->ses->capabilities & CAP_NT_SMBS)
                rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
                         desiredAccess, create_options,
-                        &fileHandle, &oplock, buf, cifs_sb->local_nls,
+                        fileHandle, oplock, buf, cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        else
                rc = -EIO; /* no NT SMB support fall into legacy open below */
@@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
                /* old server, retry the open legacy style */
                rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
                        desiredAccess, create_options,
-                       &fileHandle, &oplock, buf, cifs_sb->local_nls,
+                       fileHandle, oplock, buf, cifs_sb->local_nls,
                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        }
        if (rc) {
                cFYI(1, "cifs_create returned 0x%x", rc);
-               goto cifs_create_out;
+               goto out;
        }
 
        /* If Open reported that we actually created a file
           then we now have to set the mode if possible */
-       if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
+       if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
                struct cifs_unix_set_info_args args = {
                                .mode   = mode,
                                .ctime  = NO_CHANGE_64,
@@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
                                .device = 0,
                };
 
+               *created |= FILE_CREATED;
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                        args.uid = (__u64) current_fsuid();
                        if (inode->i_mode & S_ISGID)
@@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
                }
-               CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
+               CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
                                        current->tgid);
        } else {
                /* BB implement mode setting via Windows security
@@ -305,11 +339,11 @@ cifs_create_get_file_info:
                                              inode->i_sb, xid);
        else {
                rc = cifs_get_inode_info(&newinode, full_path, buf,
-                                        inode->i_sb, xid, &fileHandle);
+                                        inode->i_sb, xid, fileHandle);
                if (newinode) {
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
                                newinode->i_mode = mode;
-                       if ((oplock & CIFS_CREATE_ACTION) &&
+                       if ((*oplock & CIFS_CREATE_ACTION) &&
                            (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
                                newinode->i_uid = current_fsuid();
                                if (inode->i_mode & S_ISGID)
@@ -321,40 +355,139 @@ cifs_create_get_file_info:
        }
 
 cifs_create_set_dentry:
-       if (rc == 0)
-               d_instantiate(direntry, newinode);
-       else
+       if (rc != 0) {
                cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
+               goto out;
+       }
+       d_drop(direntry);
+       d_add(direntry, newinode);
 
-       if (newinode && nd) {
-               struct cifsFileInfo *pfile_info;
-               struct file *filp;
+       /* ENOENT for create?  How weird... */
+       rc = -ENOENT;
+       if (!newinode) {
+               CIFSSMBClose(xid, tcon, *fileHandle);
+               goto out;
+       }
+       rc = 0;
 
-               filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
-               if (IS_ERR(filp)) {
-                       rc = PTR_ERR(filp);
-                       CIFSSMBClose(xid, tcon, fileHandle);
-                       goto cifs_create_out;
-               }
+out:
+       kfree(buf);
+       kfree(full_path);
+       return rc;
+}
 
-               pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
-               if (pfile_info == NULL) {
-                       fput(filp);
-                       CIFSSMBClose(xid, tcon, fileHandle);
-                       rc = -ENOMEM;
-               }
-       } else {
+int
+cifs_atomic_open(struct inode *inode, struct dentry *direntry,
+                struct file *file, unsigned oflags, umode_t mode,
+                int *opened)
+{
+       int rc;
+       int xid;
+       struct tcon_link *tlink;
+       struct cifs_tcon *tcon;
+       __u16 fileHandle;
+       __u32 oplock;
+       struct file *filp;
+       struct cifsFileInfo *pfile_info;
+
+       /* Posix open is only called (at lookup time) for file create now.  For
+        * opens (rather than creates), because we do not know if it is a file
+        * or directory yet, and current Samba no longer allows us to do posix
+        * open on dirs, we could end up wasting an open call on what turns out
+        * to be a dir. For file opens, we wait to call posix open till
+        * cifs_open.  It could be added to atomic_open in the future but the
+        * performance tradeoff of the extra network request when EISDIR or
+        * EACCES is returned would have to be weighed against the 50% reduction
+        * in network traffic in the other paths.
+        */
+       if (!(oflags & O_CREAT)) {
+               struct dentry *res = cifs_lookup(inode, direntry, 0);
+               if (IS_ERR(res))
+                       return PTR_ERR(res);
+
+               return finish_no_open(file, res);
+       }
+
+       rc = check_name(direntry);
+       if (rc)
+               return rc;
+
+       xid = GetXid();
+
+       cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
+            inode, direntry->d_name.name, direntry);
+
+       tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
+       filp = ERR_CAST(tlink);
+       if (IS_ERR(tlink))
+               goto free_xid;
+
+       tcon = tlink_tcon(tlink);
+
+       rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
+                           &oplock, &fileHandle, opened);
+
+       if (rc)
+               goto out;
+
+       rc = finish_open(file, direntry, generic_file_open, opened);
+       if (rc) {
                CIFSSMBClose(xid, tcon, fileHandle);
+               goto out;
        }
 
-cifs_create_out:
-       kfree(buf);
-       kfree(full_path);
+       pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
+       if (pfile_info == NULL) {
+               CIFSSMBClose(xid, tcon, fileHandle);
+               fput(filp);
+               rc = -ENOMEM;
+       }
+
+out:
        cifs_put_tlink(tlink);
+free_xid:
        FreeXid(xid);
        return rc;
 }
 
+int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
+               bool excl)
+{
+       int rc;
+       int xid = GetXid();
+       /*
+        * BB below access is probably too much for mknod to request
+        *    but we have to do query and setpathinfo so requesting
+        *    less could fail (unless we want to request getatr and setatr
+        *    permissions (only).  At least for POSIX we do not have to
+        *    request so much.
+        */
+       unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
+       struct tcon_link *tlink;
+       __u16 fileHandle;
+       __u32 oplock;
+       int created = FILE_CREATED;
+
+       cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p",
+            inode, direntry->d_name.name, direntry);
+
+       tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
+       rc = PTR_ERR(tlink);
+       if (IS_ERR(tlink))
+               goto free_xid;
+
+       rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
+                           &oplock, &fileHandle, &created);
+       if (!rc)
+               CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
+
+       cifs_put_tlink(tlink);
+free_xid:
+       FreeXid(xid);
+
+       return rc;
+}
+
 int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
                dev_t device_number)
 {
@@ -488,20 +621,15 @@ mknod_out:
 
 struct dentry *
 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
-           struct nameidata *nd)
+           unsigned int flags)
 {
        int xid;
        int rc = 0; /* to get around spurious gcc warning, set to zero here */
-       __u32 oplock;
-       __u16 fileHandle = 0;
-       bool posix_open = false;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
        struct cifs_tcon *pTcon;
-       struct cifsFileInfo *cfile;
        struct inode *newInode = NULL;
        char *full_path = NULL;
-       struct file *filp;
 
        xid = GetXid();
 
@@ -518,31 +646,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        }
        pTcon = tlink_tcon(tlink);
 
-       oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
-
-       /*
-        * Don't allow the separator character in a path component.
-        * The VFS will not allow "/", but "\" is allowed by posix.
-        */
-       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
-               int i;
-               for (i = 0; i < direntry->d_name.len; i++)
-                       if (direntry->d_name.name[i] == '\\') {
-                               cFYI(1, "Invalid file name");
-                               rc = -EINVAL;
-                               goto lookup_out;
-                       }
-       }
-
-       /*
-        * O_EXCL: optimize away the lookup, but don't hash the dentry. Let
-        * the VFS handle the create.
-        */
-       if (nd && (nd->flags & LOOKUP_EXCL)) {
-               d_instantiate(direntry, NULL);
-               rc = 0;
+       rc = check_name(direntry);
+       if (rc)
                goto lookup_out;
-       }
 
        /* can not grab the rename sem here since it would
        deadlock in the cases (beginning of sys_rename itself)
@@ -560,80 +666,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
        }
        cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
 
-       /* Posix open is only called (at lookup time) for file create now.
-        * For opens (rather than creates), because we do not know if it
-        * is a file or directory yet, and current Samba no longer allows
-        * us to do posix open on dirs, we could end up wasting an open call
-        * on what turns out to be a dir. For file opens, we wait to call posix
-        * open till cifs_open.  It could be added here (lookup) in the future
-        * but the performance tradeoff of the extra network request when EISDIR
-        * or EACCES is returned would have to be weighed against the 50%
-        * reduction in network traffic in the other paths.
-        */
        if (pTcon->unix_ext) {
-               if (nd && !(nd->flags & LOOKUP_DIRECTORY) &&
-                    (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
-                    (nd->intent.open.file->f_flags & O_CREAT)) {
-                       rc = cifs_posix_open(full_path, &newInode,
-                                       parent_dir_inode->i_sb,
-                                       nd->intent.open.create_mode,
-                                       nd->intent.open.file->f_flags, &oplock,
-                                       &fileHandle, xid);
-                       /*
-                        * The check below works around a bug in POSIX
-                        * open in samba versions 3.3.1 and earlier where
-                        * open could incorrectly fail with invalid parameter.
-                        * If either that or op not supported returned, follow
-                        * the normal lookup.
-                        */
-                       switch (rc) {
-                       case 0:
-                               /*
-                                * The server may allow us to open things like
-                                * FIFOs, but the client isn't set up to deal
-                                * with that. If it's not a regular file, just
-                                * close it and proceed as if it were a normal
-                                * lookup.
-                                */
-                               if (newInode && !S_ISREG(newInode->i_mode)) {
-                                       CIFSSMBClose(xid, pTcon, fileHandle);
-                                       break;
-                               }
-                       case -ENOENT:
-                               posix_open = true;
-                       case -EOPNOTSUPP:
-                               break;
-                       default:
-                               pTcon->broken_posix_open = true;
-                       }
-               }
-               if (!posix_open)
-                       rc = cifs_get_inode_info_unix(&newInode, full_path,
-                                               parent_dir_inode->i_sb, xid);
-       } else
+               rc = cifs_get_inode_info_unix(&newInode, full_path,
+                                             parent_dir_inode->i_sb, xid);
+       } else {
                rc = cifs_get_inode_info(&newInode, full_path, NULL,
                                parent_dir_inode->i_sb, xid, NULL);
+       }
 
        if ((rc == 0) && (newInode != NULL)) {
                d_add(direntry, newInode);
-               if (posix_open) {
-                       filp = lookup_instantiate_filp(nd, direntry,
-                                                      generic_file_open);
-                       if (IS_ERR(filp)) {
-                               rc = PTR_ERR(filp);
-                               CIFSSMBClose(xid, pTcon, fileHandle);
-                               goto lookup_out;
-                       }
-
-                       cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
-                                                 oplock);
-                       if (cfile == NULL) {
-                               fput(filp);
-                               CIFSSMBClose(xid, pTcon, fileHandle);
-                               rc = -ENOMEM;
-                               goto lookup_out;
-                       }
-               }
                /* since paths are not looked up by component - the parent
                   directories are presumed to be good here */
                renew_parental_timestamps(direntry);
@@ -658,9 +700,9 @@ lookup_out:
 }
 
 static int
-cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
+cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 {
-       if (nd && (nd->flags & LOOKUP_RCU))
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        if (direntry->d_inode) {
@@ -689,7 +731,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
         * This may be nfsd (or something), anyway, we can't see the
         * intent of this. So, since this can be for creation, drop it.
         */
-       if (!nd)
+       if (!flags)
                return 0;
 
        /*
@@ -697,7 +739,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
         * case sensitive name which is specified by user if this is
         * for creation.
         */
-       if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+       if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
                return 0;
 
        if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
index 745da3d0653e38a0f48db4f0741f3414e44d974e..8e8bb49112ff07abcb3df80ca5d93abd3b04fc82 100644 (file)
@@ -800,7 +800,7 @@ cifs_find_inode(struct inode *inode, void *opaque)
                return 0;
 
        /* if it's not a directory or has no dentries, then flag it */
-       if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
+       if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
                fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
 
        return 1;
@@ -825,9 +825,10 @@ static bool
 inode_has_hashed_dentries(struct inode *inode)
 {
        struct dentry *dentry;
+       struct hlist_node *p;
 
        spin_lock(&inode->i_lock);
-       list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
                if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
                        spin_unlock(&inode->i_lock);
                        return true;
index 0a8224d1c4c5f2df8545f2c84f9e668feba2e0e9..a4217f02fab2860ced9f1bf444662cbf05461a4e 100644 (file)
@@ -86,9 +86,12 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
 
        dentry = d_lookup(parent, name);
        if (dentry) {
-               /* FIXME: check for inode number changes? */
-               if (dentry->d_inode != NULL)
+               inode = dentry->d_inode;
+               /* update inode in place if i_ino didn't change */
+               if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
+                       cifs_fattr_to_inode(inode, fattr);
                        return dentry;
+               }
                d_drop(dentry);
                dput(dentry);
        }
index 3097ee58fd7d432548d64f205b75a08efa133405..f25d4ea14be4b7d751e69817eca9bad2d6a14935 100644 (file)
@@ -365,16 +365,14 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
        if (mid == NULL)
                return -ENOMEM;
 
-       /* put it on the pending_mid_q */
-       spin_lock(&GlobalMid_Lock);
-       list_add_tail(&mid->qhead, &server->pending_mid_q);
-       spin_unlock(&GlobalMid_Lock);
-
        rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number);
-       if (rc)
-               delete_mid(mid);
+       if (rc) {
+               DeleteMidQEntry(mid);
+               return rc;
+       }
+
        *ret_mid = mid;
-       return rc;
+       return 0;
 }
 
 /*
@@ -407,17 +405,21 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        mid->callback_data = cbdata;
        mid->mid_state = MID_REQUEST_SUBMITTED;
 
+       /* put it on the pending_mid_q */
+       spin_lock(&GlobalMid_Lock);
+       list_add_tail(&mid->qhead, &server->pending_mid_q);
+       spin_unlock(&GlobalMid_Lock);
+
+
        cifs_in_send_inc(server);
        rc = smb_sendv(server, iov, nvec);
        cifs_in_send_dec(server);
        cifs_save_when_sent(mid);
        mutex_unlock(&server->srv_mutex);
 
-       if (rc)
-               goto out_err;
+       if (rc == 0)
+               return 0;
 
-       return rc;
-out_err:
        delete_mid(mid);
        add_credits(server, 1);
        wake_up(&server->request_q);
index 6901578761841ae6c0ed950c26de2cf64c9d1389..958ae0e0ff8c0d55d5ef18001154f56e3cb273ce 100644 (file)
@@ -89,17 +89,13 @@ int coda_cache_check(struct inode *inode, int mask)
 /* this won't do any harm: just flag all children */
 static void coda_flag_children(struct dentry *parent, int flag)
 {
-       struct list_head *child;
        struct dentry *de;
 
        spin_lock(&parent->d_lock);
-       list_for_each(child, &parent->d_subdirs)
-       {
-               de = list_entry(child, struct dentry, d_u.d_child);
+       list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
                /* don't know what to do with negative dentries */
-               if ( ! de->d_inode ) 
-                       continue;
-               coda_flag_inode(de->d_inode, flag);
+               if (de->d_inode ) 
+                       coda_flag_inode(de->d_inode, flag);
        }
        spin_unlock(&parent->d_lock);
        return; 
index 177515829062d82aed7dcdce9bda390535804614..49fe52d256009729ae9c9ec5cfd1b684255219f3 100644 (file)
@@ -30,8 +30,8 @@
 #include "coda_int.h"
 
 /* dir inode-ops */
-static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, struct nameidata *nd);
-static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd);
+static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, bool excl);
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, unsigned int flags);
 static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, 
                     struct dentry *entry);
 static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
@@ -46,7 +46,7 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
 static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
 
 /* dentry ops */
-static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
+static int coda_dentry_revalidate(struct dentry *de, unsigned int flags);
 static int coda_dentry_delete(const struct dentry *);
 
 /* support routines */
@@ -94,7 +94,7 @@ const struct file_operations coda_dir_operations = {
 
 /* inode operations for directories */
 /* access routines: lookup, readlink, permission */
-static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)
 {
        struct super_block *sb = dir->i_sb;
        const char *name = entry->d_name.name;
@@ -188,7 +188,7 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
 }
 
 /* creation routines: create, mknod, mkdir, link, symlink */
-static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, struct nameidata *nd)
+static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool excl)
 {
        int error;
        const char *name=de->d_name.name;
@@ -536,12 +536,12 @@ out:
 }
 
 /* called when a cache lookup succeeds */
-static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
+static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
 {
        struct inode *inode;
        struct coda_inode_info *cii;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = de->d_inode;
index 7e6c52d8a2074c651b116a39d56a1868d622f9f1..7414ae24a79b4690ed5fb7ed72245d941791a82f 100644 (file)
@@ -442,7 +442,7 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
 
 static struct dentry * configfs_lookup(struct inode *dir,
                                       struct dentry *dentry,
-                                      struct nameidata *nd)
+                                      unsigned int flags)
 {
        struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
        struct configfs_dirent * sd;
index d013c46402ed118ea9babda0433efd2692a447c7..28cca01ca9c9c2b29b20d16581c430d900101a78 100644 (file)
@@ -417,7 +417,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 /*
  * Lookup and fill in the inode data..
  */
-static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        unsigned int offset = 0;
        struct inode *inode = NULL;
index 40469044088def2607d19540ef0cb8dcce78ac91..8086636bf796ab328219d4a898608af1be2fdb2b 100644 (file)
@@ -218,7 +218,7 @@ static void __d_free(struct rcu_head *head)
 {
        struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
 
-       WARN_ON(!list_empty(&dentry->d_alias));
+       WARN_ON(!hlist_unhashed(&dentry->d_alias));
        if (dname_external(dentry))
                kfree(dentry->d_name.name);
        kmem_cache_free(dentry_cache, dentry); 
@@ -267,7 +267,7 @@ static void dentry_iput(struct dentry * dentry)
        struct inode *inode = dentry->d_inode;
        if (inode) {
                dentry->d_inode = NULL;
-               list_del_init(&dentry->d_alias);
+               hlist_del_init(&dentry->d_alias);
                spin_unlock(&dentry->d_lock);
                spin_unlock(&inode->i_lock);
                if (!inode->i_nlink)
@@ -291,7 +291,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
 {
        struct inode *inode = dentry->d_inode;
        dentry->d_inode = NULL;
-       list_del_init(&dentry->d_alias);
+       hlist_del_init(&dentry->d_alias);
        dentry_rcuwalk_barrier(dentry);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&inode->i_lock);
@@ -699,10 +699,11 @@ EXPORT_SYMBOL(dget_parent);
 static struct dentry *__d_find_alias(struct inode *inode, int want_discon)
 {
        struct dentry *alias, *discon_alias;
+       struct hlist_node *p;
 
 again:
        discon_alias = NULL;
-       list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
                spin_lock(&alias->d_lock);
                if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
                        if (IS_ROOT(alias) &&
@@ -737,7 +738,7 @@ struct dentry *d_find_alias(struct inode *inode)
 {
        struct dentry *de = NULL;
 
-       if (!list_empty(&inode->i_dentry)) {
+       if (!hlist_empty(&inode->i_dentry)) {
                spin_lock(&inode->i_lock);
                de = __d_find_alias(inode, 0);
                spin_unlock(&inode->i_lock);
@@ -753,9 +754,10 @@ EXPORT_SYMBOL(d_find_alias);
 void d_prune_aliases(struct inode *inode)
 {
        struct dentry *dentry;
+       struct hlist_node *p;
 restart:
        spin_lock(&inode->i_lock);
-       list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
                spin_lock(&dentry->d_lock);
                if (!dentry->d_count) {
                        __dget_dlock(dentry);
@@ -977,7 +979,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
                        inode = dentry->d_inode;
                        if (inode) {
                                dentry->d_inode = NULL;
-                               list_del_init(&dentry->d_alias);
+                               hlist_del_init(&dentry->d_alias);
                                if (dentry->d_op && dentry->d_op->d_iput)
                                        dentry->d_op->d_iput(dentry, inode);
                                else
@@ -1312,7 +1314,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
        INIT_HLIST_BL_NODE(&dentry->d_hash);
        INIT_LIST_HEAD(&dentry->d_lru);
        INIT_LIST_HEAD(&dentry->d_subdirs);
-       INIT_LIST_HEAD(&dentry->d_alias);
+       INIT_HLIST_NODE(&dentry->d_alias);
        INIT_LIST_HEAD(&dentry->d_u.d_child);
        d_set_d_op(dentry, dentry->d_sb->s_d_op);
 
@@ -1400,7 +1402,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
        if (inode) {
                if (unlikely(IS_AUTOMOUNT(inode)))
                        dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
-               list_add(&dentry->d_alias, &inode->i_dentry);
+               hlist_add_head(&dentry->d_alias, &inode->i_dentry);
        }
        dentry->d_inode = inode;
        dentry_rcuwalk_barrier(dentry);
@@ -1425,7 +1427,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
  
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
-       BUG_ON(!list_empty(&entry->d_alias));
+       BUG_ON(!hlist_unhashed(&entry->d_alias));
        if (inode)
                spin_lock(&inode->i_lock);
        __d_instantiate(entry, inode);
@@ -1458,13 +1460,14 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
        int len = entry->d_name.len;
        const char *name = entry->d_name.name;
        unsigned int hash = entry->d_name.hash;
+       struct hlist_node *p;
 
        if (!inode) {
                __d_instantiate(entry, NULL);
                return NULL;
        }
 
-       list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
                /*
                 * Don't need alias->d_lock here, because aliases with
                 * d_parent == entry->d_parent are not subject to name or
@@ -1490,7 +1493,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
 {
        struct dentry *result;
 
-       BUG_ON(!list_empty(&entry->d_alias));
+       BUG_ON(!hlist_unhashed(&entry->d_alias));
 
        if (inode)
                spin_lock(&inode->i_lock);
@@ -1531,9 +1534,9 @@ static struct dentry * __d_find_any_alias(struct inode *inode)
 {
        struct dentry *alias;
 
-       if (list_empty(&inode->i_dentry))
+       if (hlist_empty(&inode->i_dentry))
                return NULL;
-       alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias);
+       alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
        __dget(alias);
        return alias;
 }
@@ -1607,7 +1610,7 @@ struct dentry *d_obtain_alias(struct inode *inode)
        spin_lock(&tmp->d_lock);
        tmp->d_inode = inode;
        tmp->d_flags |= DCACHE_DISCONNECTED;
-       list_add(&tmp->d_alias, &inode->i_dentry);
+       hlist_add_head(&tmp->d_alias, &inode->i_dentry);
        hlist_bl_lock(&tmp->d_sb->s_anon);
        hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
        hlist_bl_unlock(&tmp->d_sb->s_anon);
@@ -2384,14 +2387,13 @@ static struct dentry *__d_unalias(struct inode *inode,
                struct dentry *dentry, struct dentry *alias)
 {
        struct mutex *m1 = NULL, *m2 = NULL;
-       struct dentry *ret;
+       struct dentry *ret = ERR_PTR(-EBUSY);
 
        /* If alias and dentry share a parent, then no extra locks required */
        if (alias->d_parent == dentry->d_parent)
                goto out_unalias;
 
        /* See lock_rename() */
-       ret = ERR_PTR(-EBUSY);
        if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex))
                goto out_err;
        m1 = &dentry->d_sb->s_vfs_rename_mutex;
@@ -2399,8 +2401,10 @@ static struct dentry *__d_unalias(struct inode *inode,
                goto out_err;
        m2 = &alias->d_parent->d_inode->i_mutex;
 out_unalias:
-       __d_move(alias, dentry);
-       ret = alias;
+       if (likely(!d_mountpoint(alias))) {
+               __d_move(alias, dentry);
+               ret = alias;
+       }
 out_err:
        spin_unlock(&inode->i_lock);
        if (m2)
@@ -2622,7 +2626,7 @@ global_root:
        if (!slash)
                error = prepend(buffer, buflen, "/", 1);
        if (!error)
-               error = real_mount(vfsmnt)->mnt_ns ? 1 : 2;
+               error = is_mounted(vfsmnt) ? 1 : 2;
        goto out;
 }
 
index b80bc846a15a55d6e8f4fefa2ad2231713616f45..d17c20fd74e6958f171e41e6c74bcf27ab620b56 100644 (file)
@@ -54,13 +54,12 @@ static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev
                        break;
                case S_IFLNK:
                        inode->i_op = &debugfs_link_operations;
-                       inode->i_fop = fops;
                        inode->i_private = data;
                        break;
                case S_IFDIR:
                        inode->i_op = &simple_dir_inode_operations;
-                       inode->i_fop = fops ? fops : &simple_dir_operations;
-                       inode->i_private = data;
+                       inode->i_fop = &simple_dir_operations;
+                       inode->i_private = NULL;
 
                        /* directory inodes start off with i_nlink == 2
                         * (for "." entry) */
@@ -91,13 +90,12 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry,
        return error;
 }
 
-static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode,
-                        void *data, const struct file_operations *fops)
+static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
        int res;
 
        mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
-       res = debugfs_mknod(dir, dentry, mode, 0, data, fops);
+       res = debugfs_mknod(dir, dentry, mode, 0, NULL, NULL);
        if (!res) {
                inc_nlink(dir);
                fsnotify_mkdir(dir, dentry);
@@ -106,10 +104,10 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode,
 }
 
 static int debugfs_link(struct inode *dir, struct dentry *dentry, umode_t mode,
-                       void *data, const struct file_operations *fops)
+                       void *data)
 {
        mode = (mode & S_IALLUGO) | S_IFLNK;
-       return debugfs_mknod(dir, dentry, mode, 0, data, fops);
+       return debugfs_mknod(dir, dentry, mode, 0, data, NULL);
 }
 
 static int debugfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
@@ -293,13 +291,19 @@ static struct file_system_type debug_fs_type = {
        .kill_sb =      kill_litter_super,
 };
 
-static int debugfs_create_by_name(const char *name, umode_t mode,
-                                 struct dentry *parent,
-                                 struct dentry **dentry,
-                                 void *data,
-                                 const struct file_operations *fops)
+struct dentry *__create_file(const char *name, umode_t mode,
+                                  struct dentry *parent, void *data,
+                                  const struct file_operations *fops)
 {
-       int error = 0;
+       struct dentry *dentry = NULL;
+       int error;
+
+       pr_debug("debugfs: creating file '%s'\n",name);
+
+       error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
+                             &debugfs_mount_count);
+       if (error)
+               goto exit;
 
        /* If the parent is not specified, we create it in the root.
         * We need the root dentry to do this, which is in the super 
@@ -309,30 +313,35 @@ static int debugfs_create_by_name(const char *name, umode_t mode,
        if (!parent)
                parent = debugfs_mount->mnt_root;
 
-       *dentry = NULL;
+       dentry = NULL;
        mutex_lock(&parent->d_inode->i_mutex);
-       *dentry = lookup_one_len(name, parent, strlen(name));
-       if (!IS_ERR(*dentry)) {
+       dentry = lookup_one_len(name, parent, strlen(name));
+       if (!IS_ERR(dentry)) {
                switch (mode & S_IFMT) {
                case S_IFDIR:
-                       error = debugfs_mkdir(parent->d_inode, *dentry, mode,
-                                             data, fops);
+                       error = debugfs_mkdir(parent->d_inode, dentry, mode);
+                                             
                        break;
                case S_IFLNK:
-                       error = debugfs_link(parent->d_inode, *dentry, mode,
-                                            data, fops);
+                       error = debugfs_link(parent->d_inode, dentry, mode,
+                                            data);
                        break;
                default:
-                       error = debugfs_create(parent->d_inode, *dentry, mode,
+                       error = debugfs_create(parent->d_inode, dentry, mode,
                                               data, fops);
                        break;
                }
-               dput(*dentry);
+               dput(dentry);
        } else
-               error = PTR_ERR(*dentry);
+               error = PTR_ERR(dentry);
        mutex_unlock(&parent->d_inode->i_mutex);
 
-       return error;
+       if (error) {
+               dentry = NULL;
+               simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+       }
+exit:
+       return dentry;
 }
 
 /**
@@ -365,25 +374,15 @@ struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops)
 {
-       struct dentry *dentry = NULL;
-       int error;
-
-       pr_debug("debugfs: creating file '%s'\n",name);
-
-       error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
-                             &debugfs_mount_count);
-       if (error)
-               goto exit;
-
-       error = debugfs_create_by_name(name, mode, parent, &dentry,
-                                      data, fops);
-       if (error) {
-               dentry = NULL;
-               simple_release_fs(&debugfs_mount, &debugfs_mount_count);
-               goto exit;
+       switch (mode & S_IFMT) {
+       case S_IFREG:
+       case 0:
+               break;
+       default:
+               BUG();
        }
-exit:
-       return dentry;
+
+       return __create_file(name, mode, parent, data, fops);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_file);
 
@@ -407,8 +406,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_file);
  */
 struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
 {
-       return debugfs_create_file(name, 
-                                  S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+       return __create_file(name, S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
                                   parent, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_dir);
@@ -446,8 +444,7 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
        if (!link)
                return NULL;
 
-       result = debugfs_create_file(name, S_IFLNK | S_IRWXUGO, parent, link,
-                                    NULL);
+       result = __create_file(name, S_IFLNK | S_IRWXUGO, parent, link, NULL);
        if (!result)
                kfree(link);
        return result;
index 979c1e309c730479fa4642f2c289fa617c94f56b..14afbabe65464e226549894404ec1af9d1a3f747 100644 (file)
@@ -439,15 +439,15 @@ static struct dentry *devpts_mount(struct file_system_type *fs_type,
                return ERR_PTR(error);
 
        if (opts.newinstance)
-               s = sget(fs_type, NULL, set_anon_super, NULL);
+               s = sget(fs_type, NULL, set_anon_super, flags, NULL);
        else
-               s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL);
+               s = sget(fs_type, compare_init_pts_sb, set_anon_super, flags,
+                        NULL);
 
        if (IS_ERR(s))
                return ERR_CAST(s);
 
        if (!s->s_root) {
-               s->s_flags = flags;
                error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
                if (error)
                        goto out_undo_sget;
index 0c85fae37666db4b18fb2bf9ebf692ae04bcbf40..1faf4cb56f3963d0945d8004b8640464b9e3b6fd 100644 (file)
@@ -1258,7 +1258,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
         */
        BUG_ON(retval == -EIOCBQUEUED);
        if (dio->is_async && retval == 0 && dio->result &&
-           ((rw & READ) || (dio->result == sdio.size)))
+           ((rw == READ) || (dio->result == sdio.size)))
                retval = -EIOCBQUEUED;
 
        if (retval != -EIOCBQUEUED)
index 534c1d46e69ea6ebb8b860137579d301f9c35840..1b5d9af937dfc4a33015eaa154a8956857381749 100644 (file)
@@ -32,7 +32,7 @@
 /**
  * ecryptfs_d_revalidate - revalidate an ecryptfs dentry
  * @dentry: The ecryptfs dentry
- * @nd: The associated nameidata
+ * @flags: lookup flags
  *
  * Called when the VFS needs to revalidate a dentry. This
  * is called whenever a name lookup finds a dentry in the
  * Returns 1 if valid, 0 otherwise.
  *
  */
-static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct dentry *lower_dentry;
        struct vfsmount *lower_mnt;
-       struct dentry *dentry_save = NULL;
-       struct vfsmount *vfsmount_save = NULL;
        int rc = 1;
 
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        lower_dentry = ecryptfs_dentry_to_lower(dentry);
        lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
        if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
                goto out;
-       if (nd) {
-               dentry_save = nd->path.dentry;
-               vfsmount_save = nd->path.mnt;
-               nd->path.dentry = lower_dentry;
-               nd->path.mnt = lower_mnt;
-       }
-       rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
-       if (nd) {
-               nd->path.dentry = dentry_save;
-               nd->path.mnt = vfsmount_save;
-       }
+       rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
        if (dentry->d_inode) {
                struct inode *lower_inode =
                        ecryptfs_inode_to_lower(dentry->d_inode);
index 867b64c5d84f9f2892e182baa89c888224b99418..989e034f02bdfa69e2c22994ceef7b06a8b61748 100644 (file)
@@ -550,20 +550,6 @@ extern struct kmem_cache *ecryptfs_key_record_cache;
 extern struct kmem_cache *ecryptfs_key_sig_cache;
 extern struct kmem_cache *ecryptfs_global_auth_tok_cache;
 extern struct kmem_cache *ecryptfs_key_tfm_cache;
-extern struct kmem_cache *ecryptfs_open_req_cache;
-
-struct ecryptfs_open_req {
-#define ECRYPTFS_REQ_PROCESSED 0x00000001
-#define ECRYPTFS_REQ_DROPPED   0x00000002
-#define ECRYPTFS_REQ_ZOMBIE    0x00000004
-       u32 flags;
-       struct file **lower_file;
-       struct dentry *lower_dentry;
-       struct vfsmount *lower_mnt;
-       wait_queue_head_t wait;
-       struct mutex mux;
-       struct list_head kthread_ctl_list;
-};
 
 struct inode *ecryptfs_get_inode(struct inode *lower_inode,
                                 struct super_block *sb);
index a07441a0a8789a9ee1e43f5be0d2b43ec3ee04e8..ffa2be57804dddcd21b89a712cc9107d027b3c3b 100644 (file)
@@ -173,7 +173,7 @@ ecryptfs_do_create(struct inode *directory_inode,
                inode = ERR_CAST(lower_dir_dentry);
                goto out;
        }
-       rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, NULL);
+       rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, true);
        if (rc) {
                printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
                       "rc = [%d]\n", __func__, rc);
@@ -240,7 +240,6 @@ out:
  * @dir: The inode of the directory in which to create the file.
  * @dentry: The eCryptfs dentry
  * @mode: The mode of the new file.
- * @nd: nameidata
  *
  * Creates a new file.
  *
@@ -248,7 +247,7 @@ out:
  */
 static int
 ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
-               umode_t mode, struct nameidata *nd)
+               umode_t mode, bool excl)
 {
        struct inode *ecryptfs_inode;
        int rc;
@@ -270,8 +269,8 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
                iput(ecryptfs_inode);
                goto out;
        }
-       d_instantiate(ecryptfs_dentry, ecryptfs_inode);
        unlock_new_inode(ecryptfs_inode);
+       d_instantiate(ecryptfs_dentry, ecryptfs_inode);
 out:
        return rc;
 }
@@ -374,7 +373,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,
  */
 static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
                                      struct dentry *ecryptfs_dentry,
-                                     struct nameidata *ecryptfs_nd)
+                                     unsigned int flags)
 {
        char *encrypted_and_encoded_name = NULL;
        size_t encrypted_and_encoded_name_size;
index 69f994a7d5249589bf594adaa4780bca967f08b2..809e67d05ca34fa32eb1363c555db71757d1a6a7 100644 (file)
 #include <linux/mount.h>
 #include "ecryptfs_kernel.h"
 
-struct kmem_cache *ecryptfs_open_req_cache;
+struct ecryptfs_open_req {
+       struct file **lower_file;
+       struct path path;
+       struct completion done;
+       struct list_head kthread_ctl_list;
+};
 
 static struct ecryptfs_kthread_ctl {
 #define ECRYPTFS_KTHREAD_ZOMBIE 0x00000001
@@ -67,18 +72,10 @@ static int ecryptfs_threadfn(void *ignored)
                        req = list_first_entry(&ecryptfs_kthread_ctl.req_list,
                                               struct ecryptfs_open_req,
                                               kthread_ctl_list);
-                       mutex_lock(&req->mux);
                        list_del(&req->kthread_ctl_list);
-                       if (!(req->flags & ECRYPTFS_REQ_ZOMBIE)) {
-                               dget(req->lower_dentry);
-                               mntget(req->lower_mnt);
-                               (*req->lower_file) = dentry_open(
-                                       req->lower_dentry, req->lower_mnt,
-                                       (O_RDWR | O_LARGEFILE), current_cred());
-                               req->flags |= ECRYPTFS_REQ_PROCESSED;
-                       }
-                       wake_up(&req->wait);
-                       mutex_unlock(&req->mux);
+                       *req->lower_file = dentry_open(&req->path,
+                               (O_RDWR | O_LARGEFILE), current_cred());
+                       complete(&req->done);
                }
                mutex_unlock(&ecryptfs_kthread_ctl.mux);
        }
@@ -111,10 +108,9 @@ void ecryptfs_destroy_kthread(void)
        ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;
        list_for_each_entry(req, &ecryptfs_kthread_ctl.req_list,
                            kthread_ctl_list) {
-               mutex_lock(&req->mux);
-               req->flags |= ECRYPTFS_REQ_ZOMBIE;
-               wake_up(&req->wait);
-               mutex_unlock(&req->mux);
+               list_del(&req->kthread_ctl_list);
+               *req->lower_file = ERR_PTR(-EIO);
+               complete(&req->done);
        }
        mutex_unlock(&ecryptfs_kthread_ctl.mux);
        kthread_stop(ecryptfs_kthread);
@@ -136,34 +132,26 @@ int ecryptfs_privileged_open(struct file **lower_file,
                             struct vfsmount *lower_mnt,
                             const struct cred *cred)
 {
-       struct ecryptfs_open_req *req;
+       struct ecryptfs_open_req req;
        int flags = O_LARGEFILE;
        int rc = 0;
 
+       init_completion(&req.done);
+       req.lower_file = lower_file;
+       req.path.dentry = lower_dentry;
+       req.path.mnt = lower_mnt;
+
        /* Corresponding dput() and mntput() are done when the
         * lower file is fput() when all eCryptfs files for the inode are
         * released. */
-       dget(lower_dentry);
-       mntget(lower_mnt);
        flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;
-       (*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred);
+       (*lower_file) = dentry_open(&req.path, flags, cred);
        if (!IS_ERR(*lower_file))
                goto out;
-       if (flags & O_RDONLY) {
+       if ((flags & O_ACCMODE) == O_RDONLY) {
                rc = PTR_ERR((*lower_file));
                goto out;
        }
-       req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);
-       if (!req) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       mutex_init(&req->mux);
-       req->lower_file = lower_file;
-       req->lower_dentry = lower_dentry;
-       req->lower_mnt = lower_mnt;
-       init_waitqueue_head(&req->wait);
-       req->flags = 0;
        mutex_lock(&ecryptfs_kthread_ctl.mux);
        if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
                rc = -EIO;
@@ -171,27 +159,14 @@ int ecryptfs_privileged_open(struct file **lower_file,
                printk(KERN_ERR "%s: We are in the middle of shutting down; "
                       "aborting privileged request to open lower file\n",
                        __func__);
-               goto out_free;
+               goto out;
        }
-       list_add_tail(&req->kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);
+       list_add_tail(&req.kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);
        mutex_unlock(&ecryptfs_kthread_ctl.mux);
        wake_up(&ecryptfs_kthread_ctl.wait);
-       wait_event(req->wait, (req->flags != 0));
-       mutex_lock(&req->mux);
-       BUG_ON(req->flags == 0);
-       if (req->flags & ECRYPTFS_REQ_DROPPED
-           || req->flags & ECRYPTFS_REQ_ZOMBIE) {
-               rc = -EIO;
-               printk(KERN_WARNING "%s: Privileged open request dropped\n",
-                      __func__);
-               goto out_unlock;
-       }
-       if (IS_ERR(*req->lower_file))
-               rc = PTR_ERR(*req->lower_file);
-out_unlock:
-       mutex_unlock(&req->mux);
-out_free:
-       kmem_cache_free(ecryptfs_open_req_cache, req);
+       wait_for_completion(&req.done);
+       if (IS_ERR(*lower_file))
+               rc = PTR_ERR(*lower_file);
 out:
        return rc;
 }
index 68954937a071abd9ce4a67b6614880a4073d1554..1c0b3b6b75c6a777948dc80338d5765345d74e95 100644 (file)
@@ -499,13 +499,12 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
                goto out;
        }
 
-       s = sget(fs_type, NULL, set_anon_super, NULL);
+       s = sget(fs_type, NULL, set_anon_super, flags, NULL);
        if (IS_ERR(s)) {
                rc = PTR_ERR(s);
                goto out;
        }
 
-       s->s_flags = flags;
        rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY);
        if (rc)
                goto out1;
@@ -682,11 +681,6 @@ static struct ecryptfs_cache_info {
                .name = "ecryptfs_key_tfm_cache",
                .size = sizeof(struct ecryptfs_key_tfm),
        },
-       {
-               .cache = &ecryptfs_open_req_cache,
-               .name = "ecryptfs_open_req_cache",
-               .size = sizeof(struct ecryptfs_open_req),
-       },
 };
 
 static void ecryptfs_free_kmem_caches(void)
index 3a06f4043df42a811add69fd7ede7b582a94c347..c0038f6566d4df1493d9321821a53adb62b902ab 100644 (file)
@@ -49,7 +49,10 @@ ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
        mutex_lock(&ecryptfs_daemon_hash_mux);
        /* TODO: Just use file->private_data? */
        rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
-       BUG_ON(rc || !daemon);
+       if (rc || !daemon) {
+               mutex_unlock(&ecryptfs_daemon_hash_mux);
+               return -EINVAL;
+       }
        mutex_lock(&daemon->mux);
        mutex_unlock(&ecryptfs_daemon_hash_mux);
        if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
@@ -122,6 +125,7 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
                goto out_unlock_daemon;
        }
        daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
+       file->private_data = daemon;
        atomic_inc(&ecryptfs_num_miscdev_opens);
 out_unlock_daemon:
        mutex_unlock(&daemon->mux);
@@ -152,9 +156,9 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file)
 
        mutex_lock(&ecryptfs_daemon_hash_mux);
        rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
-       BUG_ON(rc || !daemon);
+       if (rc || !daemon)
+               daemon = file->private_data;
        mutex_lock(&daemon->mux);
-       BUG_ON(daemon->pid != task_pid(current));
        BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
        daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
        atomic_dec(&ecryptfs_num_miscdev_opens);
@@ -191,31 +195,32 @@ int ecryptfs_send_miscdev(char *data, size_t data_size,
                          struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
                          u16 msg_flags, struct ecryptfs_daemon *daemon)
 {
-       int rc = 0;
+       struct ecryptfs_message *msg;
 
-       mutex_lock(&msg_ctx->mux);
-       msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size),
-                              GFP_KERNEL);
-       if (!msg_ctx->msg) {
-               rc = -ENOMEM;
+       msg = kmalloc((sizeof(*msg) + data_size), GFP_KERNEL);
+       if (!msg) {
                printk(KERN_ERR "%s: Out of memory whilst attempting "
                       "to kmalloc(%zd, GFP_KERNEL)\n", __func__,
-                      (sizeof(*msg_ctx->msg) + data_size));
-               goto out_unlock;
+                      (sizeof(*msg) + data_size));
+               return -ENOMEM;
        }
+
+       mutex_lock(&msg_ctx->mux);
+       msg_ctx->msg = msg;
        msg_ctx->msg->index = msg_ctx->index;
        msg_ctx->msg->data_len = data_size;
        msg_ctx->type = msg_type;
        memcpy(msg_ctx->msg->data, data, data_size);
        msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
-       mutex_lock(&daemon->mux);
        list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
+       mutex_unlock(&msg_ctx->mux);
+
+       mutex_lock(&daemon->mux);
        daemon->num_queued_msg_ctx++;
        wake_up_interruptible(&daemon->wait);
        mutex_unlock(&daemon->mux);
-out_unlock:
-       mutex_unlock(&msg_ctx->mux);
-       return rc;
+
+       return 0;
 }
 
 /*
@@ -269,8 +274,16 @@ ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
        mutex_lock(&ecryptfs_daemon_hash_mux);
        /* TODO: Just use file->private_data? */
        rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
-       BUG_ON(rc || !daemon);
+       if (rc || !daemon) {
+               mutex_unlock(&ecryptfs_daemon_hash_mux);
+               return -EINVAL;
+       }
        mutex_lock(&daemon->mux);
+       if (task_pid(current) != daemon->pid) {
+               mutex_unlock(&daemon->mux);
+               mutex_unlock(&ecryptfs_daemon_hash_mux);
+               return -EPERM;
+       }
        if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
                rc = 0;
                mutex_unlock(&ecryptfs_daemon_hash_mux);
@@ -307,9 +320,6 @@ check_list:
                 * message from the queue; try again */
                goto check_list;
        }
-       BUG_ON(euid != daemon->euid);
-       BUG_ON(current_user_ns() != daemon->user_ns);
-       BUG_ON(task_pid(current) != daemon->pid);
        msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
                                   struct ecryptfs_msg_ctx, daemon_out_list);
        BUG_ON(!msg_ctx);
index d8305b582ab00b8537443b5cff2c5f47888c723f..5528926ac7f6d06d68b6e1192bb0517785942195 100644 (file)
@@ -129,7 +129,7 @@ extern struct inode *efs_iget(struct super_block *, unsigned long);
 extern efs_block_t efs_map_block(struct inode *, efs_block_t);
 extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
-extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *efs_lookup(struct inode *, struct dentry *, unsigned int);
 extern struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
                int fh_len, int fh_type);
 extern struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
index 832b10ded82f599c27569801bf00ee8f95beff14..96f66d213a19a69fd59b9132f0bd561ce3d1d508 100644 (file)
@@ -58,7 +58,8 @@ static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len)
        return(0);
 }
 
-struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) {
+struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
        efs_ino_t inodenum;
        struct inode *inode = NULL;
 
index 74598f67efebb85e71204a832c929dd20ea96771..1c8b55670804c20e88a10a48668f574d54f58205 100644 (file)
@@ -1710,7 +1710,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                goto error_tgt_fput;
 
        /* Check if EPOLLWAKEUP is allowed */
-       if ((epds.events & EPOLLWAKEUP) && !capable(CAP_EPOLLWAKEUP))
+       if ((epds.events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND))
                epds.events &= ~EPOLLWAKEUP;
 
        /*
index fc7161d6bf6bb7d816a18314dab290e9b7cffda1..4731fd991efee11b2c05e7c45306134e07b3fe82 100644 (file)
@@ -46,7 +46,7 @@ static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
 }
 
 static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        struct inode *inode;
        ino_t ino;
@@ -60,7 +60,7 @@ static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
 }
 
 static int exofs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                        struct nameidata *nd)
+                        bool excl)
 {
        struct inode *inode = exofs_new_inode(dir, mode);
        int err = PTR_ERR(inode);
index 49cf230554a21d33785d16367d9397ab34a44d91..24a49d47e9354c00f0ebd2da6c92d3520e71332c 100644 (file)
@@ -735,13 +735,7 @@ static int _prepare_for_striping(struct ore_io_state *ios)
 out:
        ios->numdevs = devs_in_group;
        ios->pages_consumed = cur_pg;
-       if (unlikely(ret)) {
-               if (length == ios->length)
-                       return ret;
-               else
-                       ios->length -= length;
-       }
-       return 0;
+       return ret;
 }
 
 int ore_create(struct ore_io_state *ios)
index d222c77cfa1ba0669ca7580c420a1c31da35c86a..5f376d14fdcc3c0d9791fce5f2951d35b54c778b 100644 (file)
@@ -144,26 +144,26 @@ static void _sp2d_reset(struct __stripe_pages_2d *sp2d,
 {
        unsigned data_devs = sp2d->data_devs;
        unsigned group_width = data_devs + sp2d->parity;
-       unsigned p;
+       int p, c;
 
        if (!sp2d->needed)
                return;
 
-       for (p = 0; p < sp2d->pages_in_unit; p++) {
-               struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p];
-
-               if (_1ps->write_count < group_width) {
-                       unsigned c;
+       for (c = data_devs - 1; c >= 0; --c)
+               for (p = sp2d->pages_in_unit - 1; p >= 0; --p) {
+                       struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p];
 
-                       for (c = 0; c < data_devs; c++)
-                               if (_1ps->page_is_read[c]) {
-                                       struct page *page = _1ps->pages[c];
+                       if (_1ps->page_is_read[c]) {
+                               struct page *page = _1ps->pages[c];
 
-                                       r4w->put_page(priv, page);
-                                       _1ps->page_is_read[c] = false;
-                               }
+                               r4w->put_page(priv, page);
+                               _1ps->page_is_read[c] = false;
+                       }
                }
 
+       for (p = 0; p < sp2d->pages_in_unit; p++) {
+               struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p];
+
                memset(_1ps->pages, 0, group_width * sizeof(*_1ps->pages));
                _1ps->write_count = 0;
                _1ps->tx = NULL;
@@ -461,16 +461,12 @@ static void _mark_read4write_pages_uptodate(struct ore_io_state *ios, int ret)
  * ios->sp2d[p][*], xor is calculated the same way. These pages are
  * allocated/freed and don't go through cache
  */
-static int _read_4_write(struct ore_io_state *ios)
+static int _read_4_write_first_stripe(struct ore_io_state *ios)
 {
-       struct ore_io_state *ios_read;
        struct ore_striping_info read_si;
        struct __stripe_pages_2d *sp2d = ios->sp2d;
        u64 offset = ios->si.first_stripe_start;
-       u64 last_stripe_end;
-       unsigned bytes_in_stripe = ios->si.bytes_in_stripe;
-       unsigned i, c, p, min_p = sp2d->pages_in_unit, max_p = -1;
-       int ret;
+       unsigned c, p, min_p = sp2d->pages_in_unit, max_p = -1;
 
        if (offset == ios->offset) /* Go to start collect $200 */
                goto read_last_stripe;
@@ -478,6 +474,9 @@ static int _read_4_write(struct ore_io_state *ios)
        min_p = _sp2d_min_pg(sp2d);
        max_p = _sp2d_max_pg(sp2d);
 
+       ORE_DBGMSG("stripe_start=0x%llx ios->offset=0x%llx min_p=%d max_p=%d\n",
+                  offset, ios->offset, min_p, max_p);
+
        for (c = 0; ; c++) {
                ore_calc_stripe_info(ios->layout, offset, 0, &read_si);
                read_si.obj_offset += min_p * PAGE_SIZE;
@@ -512,6 +511,18 @@ static int _read_4_write(struct ore_io_state *ios)
        }
 
 read_last_stripe:
+       return 0;
+}
+
+static int _read_4_write_last_stripe(struct ore_io_state *ios)
+{
+       struct ore_striping_info read_si;
+       struct __stripe_pages_2d *sp2d = ios->sp2d;
+       u64 offset;
+       u64 last_stripe_end;
+       unsigned bytes_in_stripe = ios->si.bytes_in_stripe;
+       unsigned c, p, min_p = sp2d->pages_in_unit, max_p = -1;
+
        offset = ios->offset + ios->length;
        if (offset % PAGE_SIZE)
                _add_to_r4w_last_page(ios, &offset);
@@ -527,15 +538,15 @@ read_last_stripe:
        c = _dev_order(ios->layout->group_width * ios->layout->mirrors_p1,
                       ios->layout->mirrors_p1, read_si.par_dev, read_si.dev);
 
-       BUG_ON(ios->si.first_stripe_start + bytes_in_stripe != last_stripe_end);
-       /* unaligned IO must be within a single stripe */
-
        if (min_p == sp2d->pages_in_unit) {
                /* Didn't do it yet */
                min_p = _sp2d_min_pg(sp2d);
                max_p = _sp2d_max_pg(sp2d);
        }
 
+       ORE_DBGMSG("offset=0x%llx stripe_end=0x%llx min_p=%d max_p=%d\n",
+                  offset, last_stripe_end, min_p, max_p);
+
        while (offset < last_stripe_end) {
                struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p];
 
@@ -568,6 +579,15 @@ read_last_stripe:
        }
 
 read_it:
+       return 0;
+}
+
+static int _read_4_write_execute(struct ore_io_state *ios)
+{
+       struct ore_io_state *ios_read;
+       unsigned i;
+       int ret;
+
        ios_read = ios->ios_read_4_write;
        if (!ios_read)
                return 0;
@@ -591,6 +611,8 @@ read_it:
        }
 
        _mark_read4write_pages_uptodate(ios_read, ret);
+       ore_put_io_state(ios_read);
+       ios->ios_read_4_write = NULL; /* Might need a reuse at last stripe */
        return 0;
 }
 
@@ -626,8 +648,11 @@ int _ore_add_parity_unit(struct ore_io_state *ios,
                        /* If first stripe, Read in all read4write pages
                         * (if needed) before we calculate the first parity.
                         */
-                       _read_4_write(ios);
+                       _read_4_write_first_stripe(ios);
                }
+               if (!cur_len) /* If last stripe r4w pages of last stripe */
+                       _read_4_write_last_stripe(ios);
+               _read_4_write_execute(ios);
 
                for (i = 0; i < num_pages; i++) {
                        pages[i] = _raid_page_alloc();
@@ -654,34 +679,14 @@ int _ore_add_parity_unit(struct ore_io_state *ios,
 
 int _ore_post_alloc_raid_stuff(struct ore_io_state *ios)
 {
-       struct ore_layout *layout = ios->layout;
-
        if (ios->parity_pages) {
+               struct ore_layout *layout = ios->layout;
                unsigned pages_in_unit = layout->stripe_unit / PAGE_SIZE;
-               unsigned stripe_size = ios->si.bytes_in_stripe;
-               u64 last_stripe, first_stripe;
 
                if (_sp2d_alloc(pages_in_unit, layout->group_width,
                                layout->parity, &ios->sp2d)) {
                        return -ENOMEM;
                }
-
-               /* Round io down to last full strip */
-               first_stripe = div_u64(ios->offset, stripe_size);
-               last_stripe = div_u64(ios->offset + ios->length, stripe_size);
-
-               /* If an IO spans more then a single stripe it must end at
-                * a stripe boundary. The reminder at the end is pushed into the
-                * next IO.
-                */
-               if (last_stripe != first_stripe) {
-                       ios->length = last_stripe * stripe_size - ios->offset;
-
-                       BUG_ON(!ios->length);
-                       ios->nr_pages = (ios->length + PAGE_SIZE - 1) /
-                                       PAGE_SIZE;
-                       ios->si.length = ios->length; /*make it consistent */
-               }
        }
        return 0;
 }
index b0201ca6e9c6e0b7837917420bb3dfe1dc06b88f..29ab099e3e0818a9d9c85f0449c8df2e4b9b5f70 100644 (file)
 #define dprintk(fmt, args...) do{}while(0)
 
 
-static int get_name(struct vfsmount *mnt, struct dentry *dentry, char *name,
-               struct dentry *child);
+static int get_name(const struct path *path, char *name, struct dentry *child);
 
 
 static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
                char *name, struct dentry *child)
 {
        const struct export_operations *nop = dir->d_sb->s_export_op;
+       struct path path = {.mnt = mnt, .dentry = dir};
 
        if (nop->get_name)
                return nop->get_name(dir, name, child);
        else
-               return get_name(mnt, dir, name, child);
+               return get_name(&path, name, child);
 }
 
 /*
@@ -44,13 +44,14 @@ find_acceptable_alias(struct dentry *result,
 {
        struct dentry *dentry, *toput = NULL;
        struct inode *inode;
+       struct hlist_node *p;
 
        if (acceptable(context, result))
                return result;
 
        inode = result->d_inode;
        spin_lock(&inode->i_lock);
-       list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
                dget(dentry);
                spin_unlock(&inode->i_lock);
                if (toput)
@@ -248,11 +249,10 @@ static int filldir_one(void * __buf, const char * name, int len,
  * calls readdir on the parent until it finds an entry with
  * the same inode number as the child, and returns that.
  */
-static int get_name(struct vfsmount *mnt, struct dentry *dentry,
-               char *name, struct dentry *child)
+static int get_name(const struct path *path, char *name, struct dentry *child)
 {
        const struct cred *cred = current_cred();
-       struct inode *dir = dentry->d_inode;
+       struct inode *dir = path->dentry->d_inode;
        int error;
        struct file *file;
        struct getdents_callback buffer;
@@ -266,7 +266,7 @@ static int get_name(struct vfsmount *mnt, struct dentry *dentry,
        /*
         * Open the directory ...
         */
-       file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY, cred);
+       file = dentry_open(path, O_RDONLY, cred);
        error = PTR_ERR(file);
        if (IS_ERR(file))
                goto out;
index f663a67d7bf0b92503d0ff8561d2886d0e2796e3..73b0d9519836e1181b5b9227bd78ccead322a4d3 100644 (file)
@@ -41,8 +41,8 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
 {
        int err = ext2_add_link(dentry, inode);
        if (!err) {
-               d_instantiate(dentry, inode);
                unlock_new_inode(inode);
+               d_instantiate(dentry, inode);
                return 0;
        }
        inode_dec_link_count(inode);
@@ -55,7 +55,7 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
  * Methods themselves.
  */
 
-static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode * inode;
        ino_t ino;
@@ -94,7 +94,7 @@ struct dentry *ext2_get_parent(struct dentry *child)
  * If the create succeeds, we fill in the inode information
  * with d_instantiate(). 
  */
-static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd)
+static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
 {
        struct inode *inode;
 
@@ -242,8 +242,8 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
        if (err)
                goto out_fail;
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
 out:
        return err;
 
index b3621cb7ea31d6959943c7a2ec37e7ae2b362293..5df3d2d8169c25c1af4f45ce77a5f062517049de 100644 (file)
@@ -1184,6 +1184,12 @@ static int ext2_sync_fs(struct super_block *sb, int wait)
        struct ext2_sb_info *sbi = EXT2_SB(sb);
        struct ext2_super_block *es = EXT2_SB(sb)->s_es;
 
+       /*
+        * Write quota structures to quota file, sync_blockdev() will write
+        * them to disk later
+        */
+       dquot_writeback_dquots(sb, -1);
+
        spin_lock(&sbi->s_lock);
        if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) {
                ext2_debug("setting valid to 0\n");
index 92490e9f85ca0fc61a23f8142c0bb197758b1f1f..c8fff930790d4eba76a0810c6e75fd7a85edce85 100644 (file)
@@ -300,10 +300,11 @@ loff_t ext3_dir_llseek(struct file *file, loff_t offset, int origin)
 {
        struct inode *inode = file->f_mapping->host;
        int dx_dir = is_dx_dir(inode);
+       loff_t htree_max = ext3_get_htree_eof(file);
 
        if (likely(dx_dir))
                return generic_file_llseek_size(file, offset, origin,
-                                               ext3_get_htree_eof(file));
+                                               htree_max, htree_max);
        else
                return generic_file_llseek(file, offset, origin);
 }
index eeb63dfc5d20320b0b7876022b342920294e7754..8f4fddac01a679456c8ef867d0a2e33f6592cbee 100644 (file)
@@ -1011,7 +1011,7 @@ errout:
        return NULL;
 }
 
-static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode * inode;
        struct ext3_dir_entry_2 * de;
@@ -1671,8 +1671,8 @@ static int ext3_add_nondir(handle_t *handle,
        int err = ext3_add_entry(handle, dentry, inode);
        if (!err) {
                ext3_mark_inode_dirty(handle, inode);
-               d_instantiate(dentry, inode);
                unlock_new_inode(inode);
+               d_instantiate(dentry, inode);
                return 0;
        }
        drop_nlink(inode);
@@ -1690,7 +1690,7 @@ static int ext3_add_nondir(handle_t *handle,
  * with d_instantiate().
  */
 static int ext3_create (struct inode * dir, struct dentry * dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        handle_t *handle;
        struct inode * inode;
@@ -1836,8 +1836,8 @@ out_clear_inode:
        if (err)
                goto out_clear_inode;
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
 out_stop:
        brelse(dir_block);
        ext3_journal_stop(handle);
index 8c3a44b7c375247f54ac0d0e61be3be99e0b1d6a..4ac304c55c5327703e19ed990c39a67460f1c4ad 100644 (file)
@@ -2526,6 +2526,11 @@ static int ext3_sync_fs(struct super_block *sb, int wait)
        tid_t target;
 
        trace_ext3_sync_fs(sb, wait);
+       /*
+        * Writeback quota in non-journalled quota case - journalled quota has
+        * no dirty dquots
+        */
+       dquot_writeback_dquots(sb, -1);
        if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) {
                if (wait)
                        log_wait_commit(EXT3_SB(sb)->s_journal, target);
index aa39e600d15954244aead38f7aed30513ce86d65..8e07d2a5a13952836c820c32419f340b148a8ce2 100644 (file)
@@ -324,74 +324,27 @@ static inline loff_t ext4_get_htree_eof(struct file *filp)
 
 
 /*
- * ext4_dir_llseek() based on generic_file_llseek() to handle both
- * non-htree and htree directories, where the "offset" is in terms
- * of the filename hash value instead of the byte offset.
+ * ext4_dir_llseek() calls generic_file_llseek_size to handle htree
+ * directories, where the "offset" is in terms of the filename hash
+ * value instead of the byte offset.
  *
- * NOTE: offsets obtained *before* ext4_set_inode_flag(dir, EXT4_INODE_INDEX)
- *       will be invalid once the directory was converted into a dx directory
+ * Because we may return a 64-bit hash that is well beyond offset limits,
+ * we need to pass the max hash as the maximum allowable offset in
+ * the htree directory case.
+ *
+ * For non-htree, ext4_llseek already chooses the proper max offset.
  */
 loff_t ext4_dir_llseek(struct file *file, loff_t offset, int origin)
 {
        struct inode *inode = file->f_mapping->host;
-       loff_t ret = -EINVAL;
        int dx_dir = is_dx_dir(inode);
+       loff_t htree_max = ext4_get_htree_eof(file);
 
-       mutex_lock(&inode->i_mutex);
-
-       /* NOTE: relative offsets with dx directories might not work
-        *       as expected, as it is difficult to figure out the
-        *       correct offset between dx hashes */
-
-       switch (origin) {
-       case SEEK_END:
-               if (unlikely(offset > 0))
-                       goto out_err; /* not supported for directories */
-
-               /* so only negative offsets are left, does that have a
-                * meaning for directories at all? */
-               if (dx_dir)
-                       offset += ext4_get_htree_eof(file);
-               else
-                       offset += inode->i_size;
-               break;
-       case SEEK_CUR:
-               /*
-                * Here we special-case the lseek(fd, 0, SEEK_CUR)
-                * position-querying operation.  Avoid rewriting the "same"
-                * f_pos value back to the file because a concurrent read(),
-                * write() or lseek() might have altered it
-                */
-               if (offset == 0) {
-                       offset = file->f_pos;
-                       goto out_ok;
-               }
-
-               offset += file->f_pos;
-               break;
-       }
-
-       if (unlikely(offset < 0))
-               goto out_err;
-
-       if (!dx_dir) {
-               if (offset > inode->i_sb->s_maxbytes)
-                       goto out_err;
-       } else if (offset > ext4_get_htree_eof(file))
-               goto out_err;
-
-       /* Special lock needed here? */
-       if (offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
-
-out_ok:
-       ret = offset;
-out_err:
-       mutex_unlock(&inode->i_mutex);
-
-       return ret;
+       if (likely(dx_dir))
+               return generic_file_llseek_size(file, offset, origin,
+                                                   htree_max, htree_max);
+       else
+               return ext4_llseek(file, offset, origin);
 }
 
 /*
index 8c7642a00054fd1ddf649e733e4b6efb5a0eb14b..782eecb57e43a33ed5d6485f9490140ae6d88255 100644 (file)
@@ -211,9 +211,9 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 }
 
 /*
- * ext4_llseek() copied from generic_file_llseek() to handle both
- * block-mapped and extent-mapped maxbytes values. This should
- * otherwise be identical with generic_file_llseek().
+ * ext4_llseek() handles both block-mapped and extent-mapped maxbytes values
+ * by calling generic_file_llseek_size() with the appropriate maxbytes
+ * value for each.
  */
 loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
 {
@@ -225,7 +225,8 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
        else
                maxbytes = inode->i_sb->s_maxbytes;
 
-       return generic_file_llseek_size(file, offset, origin, maxbytes);
+       return generic_file_llseek_size(file, offset, origin,
+                                       maxbytes, i_size_read(inode));
 }
 
 const struct file_operations ext4_file_operations = {
index bb6c7d8113134ee7796a141065d9ed602650f10e..2a1dcea4f12ef91fd94a154f0d1cad8816af7ed8 100644 (file)
@@ -135,14 +135,7 @@ static int ext4_sync_parent(struct inode *inode)
        inode = igrab(inode);
        while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
                ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
-               dentry = NULL;
-               spin_lock(&inode->i_lock);
-               if (!list_empty(&inode->i_dentry)) {
-                       dentry = list_first_entry(&inode->i_dentry,
-                                                 struct dentry, d_alias);
-                       dget(dentry);
-               }
-               spin_unlock(&inode->i_lock);
+               dentry = d_find_any_alias(inode);
                if (!dentry)
                        break;
                next = igrab(dentry->d_parent->d_inode);
@@ -232,7 +225,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 
        if (!journal) {
                ret = __sync_inode(inode, datasync);
-               if (!ret && !list_empty(&inode->i_dentry))
+               if (!ret && !hlist_empty(&inode->i_dentry))
                        ret = ext4_sync_parent(inode);
                goto out;
        }
index e34deac3f3663ee3fdaf7d19b44acf5eab45d6ca..7f7dad7876035e474b3c9ad7054344f6f6e7d045 100644 (file)
@@ -268,7 +268,6 @@ group_extend_out:
                err = ext4_move_extents(filp, donor_filp, me.orig_start,
                                        me.donor_start, me.len, &me.moved_len);
                mnt_drop_write_file(filp);
-               mnt_drop_write(filp->f_path.mnt);
 
                if (copy_to_user((struct move_extent __user *)arg,
                                 &me, sizeof(me)))
@@ -390,7 +389,7 @@ group_add_out:
                if (err)
                        return err;
 
-               err = mnt_want_write(filp->f_path.mnt);
+               err = mnt_want_write_file(filp);
                if (err)
                        goto resizefs_out;
 
@@ -402,7 +401,7 @@ group_add_out:
                }
                if (err == 0)
                        err = err2;
-               mnt_drop_write(filp->f_path.mnt);
+               mnt_drop_write_file(filp);
 resizefs_out:
                ext4_resize_end(sb);
                return err;
index 5845cd97bf8b094b0fc01082279e8d65ee73f241..d0d3f0e87f997ce589f64321dec35e103c98d2d7 100644 (file)
@@ -1312,7 +1312,7 @@ errout:
        return NULL;
 }
 
-static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode;
        struct ext4_dir_entry_2 *de;
@@ -2072,8 +2072,8 @@ static int ext4_add_nondir(handle_t *handle,
        int err = ext4_add_entry(handle, dentry, inode);
        if (!err) {
                ext4_mark_inode_dirty(handle, inode);
-               d_instantiate(dentry, inode);
                unlock_new_inode(inode);
+               d_instantiate(dentry, inode);
                return 0;
        }
        drop_nlink(inode);
@@ -2091,7 +2091,7 @@ static int ext4_add_nondir(handle_t *handle,
  * with d_instantiate().
  */
 static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                      struct nameidata *nd)
+                      bool excl)
 {
        handle_t *handle;
        struct inode *inode;
@@ -2249,8 +2249,8 @@ out_clear_inode:
        err = ext4_mark_inode_dirty(handle, dir);
        if (err)
                goto out_clear_inode;
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
 out_stop:
        brelse(dir_block);
        ext4_journal_stop(handle);
index eb7aa3e4ef05caf136f24e0565a28e6d1e0a1539..d8759401ecae835f696b8f648f4d2ff9883da8c9 100644 (file)
@@ -4325,6 +4325,11 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
 
        trace_ext4_sync_fs(sb, wait);
        flush_workqueue(sbi->dio_unwritten_wq);
+       /*
+        * Writeback quota in non-journalled quota case - journalled quota has
+        * no dirty dquots
+        */
+       dquot_writeback_dquots(sb, -1);
        if (jbd2_journal_start_commit(sbi->s_journal, &target)) {
                if (wait)
                        jbd2_log_wait_commit(sbi->s_journal, target);
index a3d81ebf6d864a8c2189147e5771c435473b2e42..0038b32cb36276d537f2ec81a46469bf3ad221b1 100644 (file)
@@ -738,22 +738,21 @@ static int
 fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent)
 {
        int len = *lenp;
-       u32 ipos_h, ipos_m, ipos_l;
+       struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+       loff_t i_pos;
 
        if (len < 5) {
                *lenp = 5;
                return 255; /* no room */
        }
 
-       ipos_h = MSDOS_I(inode)->i_pos >> 8;
-       ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
-       ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28;
+       i_pos = fat_i_pos_read(sbi, inode);
        *lenp = 5;
        fh[0] = inode->i_ino;
        fh[1] = inode->i_generation;
-       fh[2] = ipos_h;
-       fh[3] = ipos_m | MSDOS_I(inode)->i_logstart;
-       fh[4] = ipos_l;
+       fh[2] = i_pos >> 8;
+       fh[3] = ((i_pos & 0xf0) << 24) | MSDOS_I(inode)->i_logstart;
+       fh[4] = (i_pos & 0x0f) << 28;
        if (parent)
                fh[4] |= MSDOS_I(parent)->i_logstart;
        return 3;
index c5938c9084b9796794626d4dc08bd42c0030b283..70d993a9380572bac393a45f3dcb9896db404f9e 100644 (file)
@@ -201,7 +201,7 @@ static const struct dentry_operations msdos_dentry_operations = {
 
 /***** Get inode using directory and name */
 static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        struct super_block *sb = dir->i_sb;
        struct fat_slot_info sinfo;
@@ -265,7 +265,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
 
 /***** Create a file */
 static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                       struct nameidata *nd)
+                       bool excl)
 {
        struct super_block *sb = dir->i_sb;
        struct inode *inode = NULL;
index 98ae804f5273df49ba857f8853d83ba7503c4255..6cc480652433b66a52c42cbcd3bde3f19e348f30 100644 (file)
@@ -41,9 +41,9 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
        return ret;
 }
 
-static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int vfat_revalidate(struct dentry *dentry, unsigned int flags)
 {
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        /* This is not negative dentry. Always valid. */
@@ -52,9 +52,9 @@ static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
        return vfat_revalidate_shortname(dentry);
 }
 
-static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
+static int vfat_revalidate_ci(struct dentry *dentry, unsigned int flags)
 {
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        /*
@@ -74,7 +74,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
         * This may be nfsd (or something), anyway, we can't see the
         * intent of this. So, since this can be for creation, drop it.
         */
-       if (!nd)
+       if (!flags)
                return 0;
 
        /*
@@ -82,7 +82,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
         * case sensitive name which is specified by user if this is
         * for creation.
         */
-       if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+       if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
                return 0;
 
        return vfat_revalidate_shortname(dentry);
@@ -714,7 +714,7 @@ static int vfat_d_anon_disconn(struct dentry *dentry)
 }
 
 static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
-                                 struct nameidata *nd)
+                                 unsigned int flags)
 {
        struct super_block *sb = dir->i_sb;
        struct fat_slot_info sinfo;
@@ -772,7 +772,7 @@ error:
 }
 
 static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                      struct nameidata *nd)
+                      bool excl)
 {
        struct super_block *sb = dir->i_sb;
        struct inode *inode;
index b1a524d798e720cf18ad7ad4decdab430a2b9c5e..cf6f4345ceb0125baf86b7a029e7fdf8712f76c3 100644 (file)
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -14,7 +14,7 @@
 #include <linux/sched.h>
 #include <linux/pipe_fs_i.h>
 
-static void wait_for_partner(struct inode* inode, unsigned int *cnt)
+static int wait_for_partner(struct inode* inode, unsigned int *cnt)
 {
        int cur = *cnt; 
 
@@ -23,6 +23,7 @@ static void wait_for_partner(struct inode* inode, unsigned int *cnt)
                if (signal_pending(current))
                        break;
        }
+       return cur == *cnt ? -ERESTARTSYS : 0;
 }
 
 static void wake_up_partner(struct inode* inode)
@@ -67,8 +68,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
                                 * seen a writer */
                                filp->f_version = pipe->w_counter;
                        } else {
-                               wait_for_partner(inode, &pipe->w_counter);
-                               if(signal_pending(current))
+                               if (wait_for_partner(inode, &pipe->w_counter))
                                        goto err_rd;
                        }
                }
@@ -90,8 +90,7 @@ static int fifo_open(struct inode *inode, struct file *filp)
                        wake_up_partner(inode);
 
                if (!pipe->readers) {
-                       wait_for_partner(inode, &pipe->r_counter);
-                       if (signal_pending(current))
+                       if (wait_for_partner(inode, &pipe->r_counter))
                                goto err_wr;
                }
                break;
index a305d9e2d1b2aac05dcd456bdd23885652272439..b3fc4d67a26b31243474520bfbcddacce3733ded 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/lglock.h>
 #include <linux/percpu_counter.h>
 #include <linux/percpu.h>
+#include <linux/hardirq.h>
+#include <linux/task_work.h>
 #include <linux/ima.h>
 
 #include <linux/atomic.h>
@@ -251,7 +253,6 @@ static void __fput(struct file *file)
        }
        fops_put(file->f_op);
        put_pid(file->f_owner.pid);
-       file_sb_list_del(file);
        if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
                i_readcount_dec(inode);
        if (file->f_mode & FMODE_WRITE)
@@ -263,10 +264,77 @@ static void __fput(struct file *file)
        mntput(mnt);
 }
 
+static DEFINE_SPINLOCK(delayed_fput_lock);
+static LIST_HEAD(delayed_fput_list);
+static void delayed_fput(struct work_struct *unused)
+{
+       LIST_HEAD(head);
+       spin_lock_irq(&delayed_fput_lock);
+       list_splice_init(&delayed_fput_list, &head);
+       spin_unlock_irq(&delayed_fput_lock);
+       while (!list_empty(&head)) {
+               struct file *f = list_first_entry(&head, struct file, f_u.fu_list);
+               list_del_init(&f->f_u.fu_list);
+               __fput(f);
+       }
+}
+
+static void ____fput(struct callback_head *work)
+{
+       __fput(container_of(work, struct file, f_u.fu_rcuhead));
+}
+
+/*
+ * If kernel thread really needs to have the final fput() it has done
+ * to complete, call this.  The only user right now is the boot - we
+ * *do* need to make sure our writes to binaries on initramfs has
+ * not left us with opened struct file waiting for __fput() - execve()
+ * won't work without that.  Please, don't add more callers without
+ * very good reasons; in particular, never call that with locks
+ * held and never call that from a thread that might need to do
+ * some work on any kind of umount.
+ */
+void flush_delayed_fput(void)
+{
+       delayed_fput(NULL);
+}
+
+static DECLARE_WORK(delayed_fput_work, delayed_fput);
+
 void fput(struct file *file)
 {
-       if (atomic_long_dec_and_test(&file->f_count))
+       if (atomic_long_dec_and_test(&file->f_count)) {
+               struct task_struct *task = current;
+               file_sb_list_del(file);
+               if (unlikely(in_interrupt() || task->flags & PF_KTHREAD)) {
+                       unsigned long flags;
+                       spin_lock_irqsave(&delayed_fput_lock, flags);
+                       list_add(&file->f_u.fu_list, &delayed_fput_list);
+                       schedule_work(&delayed_fput_work);
+                       spin_unlock_irqrestore(&delayed_fput_lock, flags);
+                       return;
+               }
+               init_task_work(&file->f_u.fu_rcuhead, ____fput);
+               task_work_add(task, &file->f_u.fu_rcuhead, true);
+       }
+}
+
+/*
+ * synchronous analog of fput(); for kernel threads that might be needed
+ * in some umount() (and thus can't use flush_delayed_fput() without
+ * risking deadlocks), need to wait for completion of __fput() and know
+ * for this specific struct file it won't involve anything that would
+ * need them.  Use only if you really need it - at the very least,
+ * don't blindly convert fput() by kernel thread to that.
+ */
+void __fput_sync(struct file *file)
+{
+       if (atomic_long_dec_and_test(&file->f_count)) {
+               struct task_struct *task = current;
+               file_sb_list_del(file);
+               BUG_ON(!(task->flags & PF_KTHREAD));
                __fput(file);
+       }
 }
 
 EXPORT_SYMBOL(fput);
@@ -483,10 +551,8 @@ void mark_files_ro(struct super_block *sb)
 {
        struct file *f;
 
-retry:
        lg_global_lock(&files_lglock);
        do_file_list_for_each_entry(sb, f) {
-               struct vfsmount *mnt;
                if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
                       continue;
                if (!file_count(f))
@@ -499,12 +565,7 @@ retry:
                if (file_check_writeable(f) != 0)
                        continue;
                file_release_write(f);
-               mnt = mntget(f->f_path.mnt);
-               /* This can sleep, so we can't hold the spinlock. */
-               lg_global_unlock(&files_lglock);
-               mnt_drop_write(mnt);
-               mntput(mnt);
-               goto retry;
+               mnt_drop_write_file(f);
        } while_file_list_for_each_entry;
        lg_global_unlock(&files_lglock);
 }
index 3360f1e678ad1c0eef52994f4b44342854ef621e..bd447e88f208d2671ed5d13a054ad39cffc51e7b 100644 (file)
@@ -48,7 +48,7 @@
 #define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
 
 
-static struct dentry * vxfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int);
 static int             vxfs_readdir(struct file *, void *, filldir_t);
 
 const struct inode_operations vxfs_dir_inode_ops = {
@@ -203,7 +203,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
  *   in the return pointer.
  */
 static struct dentry *
-vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
+vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
 {
        struct inode            *ip = NULL;
        ino_t                   ino;
index 41a3ccff18d87bdfc3f65148e2f39f8067f3a8ce..8f660dd6137a1105ba648e1a1412ffc5900c1233 100644 (file)
@@ -1315,6 +1315,8 @@ void writeback_inodes_sb_nr(struct super_block *sb,
                .reason                 = reason,
        };
 
+       if (sb->s_bdi == &noop_backing_dev_info)
+               return;
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
        bdi_queue_work(sb->s_bdi, &work);
        wait_for_completion(&done);
@@ -1398,6 +1400,9 @@ void sync_inodes_sb(struct super_block *sb)
                .reason         = WB_REASON_SYNC,
        };
 
+       /* Nothing to do? */
+       if (sb->s_bdi == &noop_backing_dev_info)
+               return;
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
 
        bdi_queue_work(sb->s_bdi, &work);
index e159e682ad4c68b16b82ef7eeafa889c05877580..5df4775fea03638f14d1408cfe16408e8a0ed6d7 100644 (file)
@@ -6,18 +6,6 @@
 #include <linux/fs_struct.h>
 #include "internal.h"
 
-static inline void path_get_longterm(struct path *path)
-{
-       path_get(path);
-       mnt_make_longterm(path->mnt);
-}
-
-static inline void path_put_longterm(struct path *path)
-{
-       mnt_make_shortterm(path->mnt);
-       path_put(path);
-}
-
 /*
  * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
  * It can block.
@@ -26,7 +14,7 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
 {
        struct path old_root;
 
-       path_get_longterm(path);
+       path_get(path);
        spin_lock(&fs->lock);
        write_seqcount_begin(&fs->seq);
        old_root = fs->root;
@@ -34,7 +22,7 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
        write_seqcount_end(&fs->seq);
        spin_unlock(&fs->lock);
        if (old_root.dentry)
-               path_put_longterm(&old_root);
+               path_put(&old_root);
 }
 
 /*
@@ -45,7 +33,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
 {
        struct path old_pwd;
 
-       path_get_longterm(path);
+       path_get(path);
        spin_lock(&fs->lock);
        write_seqcount_begin(&fs->seq);
        old_pwd = fs->pwd;
@@ -54,7 +42,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
        spin_unlock(&fs->lock);
 
        if (old_pwd.dentry)
-               path_put_longterm(&old_pwd);
+               path_put(&old_pwd);
 }
 
 static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
@@ -84,7 +72,7 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
                        write_seqcount_end(&fs->seq);
                        while (hits--) {
                                count++;
-                               path_get_longterm(new_root);
+                               path_get(new_root);
                        }
                        spin_unlock(&fs->lock);
                }
@@ -92,13 +80,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
        while (count--)
-               path_put_longterm(old_root);
+               path_put(old_root);
 }
 
 void free_fs_struct(struct fs_struct *fs)
 {
-       path_put_longterm(&fs->root);
-       path_put_longterm(&fs->pwd);
+       path_put(&fs->root);
+       path_put(&fs->pwd);
        kmem_cache_free(fs_cachep, fs);
 }
 
@@ -132,9 +120,9 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
 
                spin_lock(&old->lock);
                fs->root = old->root;
-               path_get_longterm(&fs->root);
+               path_get(&fs->root);
                fs->pwd = old->pwd;
-               path_get_longterm(&fs->pwd);
+               path_get(&fs->pwd);
                spin_unlock(&old->lock);
        }
        return fs;
index 334e0b18a014c72bf78583f76a6c3b02f9058181..8964cf3999b2bb561ec71d93914170529f72977a 100644 (file)
@@ -154,7 +154,7 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
  * the lookup once more.  If the lookup results in the same inode,
  * then refresh the attributes, timeouts and mark the dentry valid.
  */
-static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
+static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
 {
        struct inode *inode;
 
@@ -174,7 +174,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
                if (!inode)
                        return 0;
 
-               if (nd && (nd->flags & LOOKUP_RCU))
+               if (flags & LOOKUP_RCU)
                        return -ECHILD;
 
                fc = get_fuse_conn(inode);
@@ -249,7 +249,7 @@ static struct dentry *fuse_d_add_directory(struct dentry *entry,
                /* This tries to shrink the subtree below alias */
                fuse_invalidate_entry(alias);
                dput(alias);
-               if (!list_empty(&inode->i_dentry))
+               if (!hlist_empty(&inode->i_dentry))
                        return ERR_PTR(-EBUSY);
        } else {
                dput(alias);
@@ -316,7 +316,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
 }
 
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
-                                 struct nameidata *nd)
+                                 unsigned int flags)
 {
        int err;
        struct fuse_entry_out outarg;
@@ -370,7 +370,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
  * 'mknod' + 'open' requests.
  */
 static int fuse_create_open(struct inode *dir, struct dentry *entry,
-                           umode_t mode, struct nameidata *nd)
+                           struct file *file, unsigned flags,
+                           umode_t mode, int *opened)
 {
        int err;
        struct inode *inode;
@@ -381,15 +382,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
        struct fuse_open_out outopen;
        struct fuse_entry_out outentry;
        struct fuse_file *ff;
-       struct file *file;
-       int flags = nd->intent.open.flags;
-
-       if (fc->no_create)
-               return -ENOSYS;
 
        forget = fuse_alloc_forget();
+       err = -ENOMEM;
        if (!forget)
-               return -ENOMEM;
+               goto out_err;
 
        req = fuse_get_req(fc);
        err = PTR_ERR(req);
@@ -428,11 +425,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
        req->out.args[1].value = &outopen;
        fuse_request_send(fc, req);
        err = req->out.h.error;
-       if (err) {
-               if (err == -ENOSYS)
-                       fc->no_create = 1;
+       if (err)
                goto out_free_ff;
-       }
 
        err = -EIO;
        if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
@@ -448,28 +442,74 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
                flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
                fuse_sync_release(ff, flags);
                fuse_queue_forget(fc, forget, outentry.nodeid, 1);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out_err;
        }
        kfree(forget);
        d_instantiate(entry, inode);
        fuse_change_entry_timeout(entry, &outentry);
        fuse_invalidate_attr(dir);
-       file = lookup_instantiate_filp(nd, entry, generic_file_open);
-       if (IS_ERR(file)) {
+       err = finish_open(file, entry, generic_file_open, opened);
+       if (err) {
                fuse_sync_release(ff, flags);
-               return PTR_ERR(file);
+       } else {
+               file->private_data = fuse_file_get(ff);
+               fuse_finish_open(inode, file);
        }
-       file->private_data = fuse_file_get(ff);
-       fuse_finish_open(inode, file);
-       return 0;
+       return err;
 
- out_free_ff:
+out_free_ff:
        fuse_file_free(ff);
- out_put_request:
+out_put_request:
        fuse_put_request(fc, req);
- out_put_forget_req:
+out_put_forget_req:
        kfree(forget);
+out_err:
+       return err;
+}
+
+static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t);
+static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
+                           struct file *file, unsigned flags,
+                           umode_t mode, int *opened)
+{
+       int err;
+       struct fuse_conn *fc = get_fuse_conn(dir);
+       struct dentry *res = NULL;
+
+       if (d_unhashed(entry)) {
+               res = fuse_lookup(dir, entry, 0);
+               if (IS_ERR(res))
+                       return PTR_ERR(res);
+
+               if (res)
+                       entry = res;
+       }
+
+       if (!(flags & O_CREAT) || entry->d_inode)
+               goto no_open;
+
+       /* Only creates */
+       *opened |= FILE_CREATED;
+
+       if (fc->no_create)
+               goto mknod;
+
+       err = fuse_create_open(dir, entry, file, flags, mode, opened);
+       if (err == -ENOSYS) {
+               fc->no_create = 1;
+               goto mknod;
+       }
+out_dput:
+       dput(res);
        return err;
+
+mknod:
+       err = fuse_mknod(dir, entry, mode, 0);
+       if (err)
+               goto out_dput;
+no_open:
+       return finish_no_open(file, res);
 }
 
 /*
@@ -571,14 +611,8 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
 }
 
 static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode,
-                      struct nameidata *nd)
+                      bool excl)
 {
-       if (nd) {
-               int err = fuse_create_open(dir, entry, mode, nd);
-               if (err != -ENOSYS)
-                       return err;
-               /* Fall back on mknod */
-       }
        return fuse_mknod(dir, entry, mode, 0);
 }
 
@@ -1646,6 +1680,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
        .link           = fuse_link,
        .setattr        = fuse_setattr,
        .create         = fuse_create,
+       .atomic_open    = fuse_atomic_open,
        .mknod          = fuse_mknod,
        .permission     = fuse_permission,
        .getattr        = fuse_getattr,
index 0da8da2c991d30a906f954ce021f5373092298f9..4fddb3c22d258ca6da35b4e743ec80fc20ee2e08 100644 (file)
@@ -25,7 +25,7 @@
 /**
  * gfs2_drevalidate - Check directory lookup consistency
  * @dentry: the mapping to check
- * @nd:
+ * @flags: lookup flags
  *
  * Check to make sure the lookup necessary to arrive at this inode from its
  * parent is still good.
@@ -33,7 +33,7 @@
  * Returns: 1 if the dentry is ok, 0 if it isn't
  */
 
-static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
+static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
 {
        struct dentry *parent;
        struct gfs2_sbd *sdp;
@@ -44,7 +44,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
        int error;
        int had_lock = 0;
 
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        parent = dget_parent(dentry);
index a9ba2444e077ac145f23c25161038a0f8ac2f468..867674785fcf04909ae03cd5d6f95752fcaeee6d 100644 (file)
@@ -755,11 +755,8 @@ fail:
  */
 
 static int gfs2_create(struct inode *dir, struct dentry *dentry,
-                      umode_t mode, struct nameidata *nd)
+                      umode_t mode, bool excl)
 {
-       int excl = 0;
-       if (nd && (nd->flags & LOOKUP_EXCL))
-               excl = 1;
        return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
 }
 
@@ -775,7 +772,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
  */
 
 static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
-                                 struct nameidata *nd)
+                                 unsigned int flags)
 {
        struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0);
        if (inode && !IS_ERR(inode)) {
index b8c250fc4922e8dd501a0c12c1481f7d1a32e0d8..6c906078f657024c6f17c663b413a97de643e8b0 100644 (file)
@@ -1286,7 +1286,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
                error = -EBUSY;
                goto error_bdev;
        }
-       s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev);
+       s = sget(fs_type, test_gfs2_super, set_gfs2_super, flags, bdev);
        mutex_unlock(&bdev->bd_fsfreeze_mutex);
        error = PTR_ERR(s);
        if (IS_ERR(s))
@@ -1316,7 +1316,6 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
        } else {
                char b[BDEVNAME_SIZE];
 
-               s->s_flags = flags;
                s->s_mode = mode;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                sb_set_blocksize(s, block_size(bdev));
@@ -1360,7 +1359,7 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type,
                       dev_name, error);
                return ERR_PTR(error);
        }
-       s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super,
+       s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, flags,
                 path.dentry->d_inode->i_sb->s_bdev);
        path_put(&path);
        if (IS_ERR(s)) {
index b97178e7d397d3e767694622779ace8716c4d6f3..27b5cc7d688166d4e9a74525d6e1ad00133fe94f 100644 (file)
@@ -1108,7 +1108,7 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
        }
 }
 
-int gfs2_quota_sync(struct super_block *sb, int type, int wait)
+int gfs2_quota_sync(struct super_block *sb, int type)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_quota_data **qda;
@@ -1154,7 +1154,7 @@ int gfs2_quota_sync(struct super_block *sb, int type, int wait)
 
 static int gfs2_quota_sync_timeo(struct super_block *sb, int type)
 {
-       return gfs2_quota_sync(sb, type, 0);
+       return gfs2_quota_sync(sb, type);
 }
 
 int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
index 90bf1c302a983df6c74191f5c2341b8cf5c70f69..f25d98b87904aa7ab315c8668b90b556c67dcf90 100644 (file)
@@ -26,7 +26,7 @@ extern int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid);
 extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
                              u32 uid, u32 gid);
 
-extern int gfs2_quota_sync(struct super_block *sb, int type, int wait);
+extern int gfs2_quota_sync(struct super_block *sb, int type);
 extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id);
 
 extern int gfs2_quota_init(struct gfs2_sbd *sdp);
index 713e621c240b9e6989ea50b7fa0a0c4f3b5f111d..f3d6bbfb32c5308e9893fe6c689bf1935af2bc50 100644 (file)
@@ -838,7 +838,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
        int error;
 
        flush_workqueue(gfs2_delete_workqueue);
-       gfs2_quota_sync(sdp->sd_vfs, 0, 1);
+       gfs2_quota_sync(sdp->sd_vfs, 0);
        gfs2_statfs_sync(sdp->sd_vfs, 0);
 
        error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
@@ -952,6 +952,8 @@ restart:
 static int gfs2_sync_fs(struct super_block *sb, int wait)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
+
+       gfs2_quota_sync(sb, -1);
        if (wait && sdp)
                gfs2_log_flush(sdp, NULL);
        return 0;
index 9c2592b1d5ff74ab0e5c2f800b0d0e4508119021..73ecc34c434280ec0c7343ca0f801ea08c784f6e 100644 (file)
@@ -168,7 +168,7 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
        if (simple_strtol(buf, NULL, 0) != 1)
                return -EINVAL;
 
-       gfs2_quota_sync(sdp->sd_vfs, 0, 1);
+       gfs2_quota_sync(sdp->sd_vfs, 0);
        return len;
 }
 
index 62fc14ea4b7387549d2f7017345070864a0d182d..422dde2ec0a1ecc99f5d129136e044e5ee0a1f1b 100644 (file)
@@ -18,7 +18,7 @@
  * hfs_lookup()
  */
 static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
-                                struct nameidata *nd)
+                                unsigned int flags)
 {
        hfs_cat_rec rec;
        struct hfs_find_data fd;
@@ -187,7 +187,7 @@ static int hfs_dir_release(struct inode *inode, struct file *file)
  * the directory and the name (and its length) of the new file.
  */
 static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                     struct nameidata *nd)
+                     bool excl)
 {
        struct inode *inode;
        int res;
index 2c16316d291794a875b5afc36908829cfe1f5ce5..a67955a0c36f621e8ca935c50f769a4b5023a1e4 100644 (file)
@@ -432,7 +432,7 @@ out:
                if (inode->i_ino < HFS_FIRSTUSER_CNID)
                        set_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags);
                set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-               sb->s_dirt = 1;
+               hfs_mark_mdb_dirty(sb);
        }
        return res;
 
index 1bf967c6bfdc6cb1b129887135f47608652b6311..8275175acf6eaaf8606b940d6f05c96d7ae08a5c 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mutex.h>
 #include <linux/buffer_head.h>
 #include <linux/fs.h>
+#include <linux/workqueue.h>
 
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
@@ -137,16 +138,15 @@ struct hfs_sb_info {
        gid_t s_gid;                            /* The gid of all files */
 
        int session, part;
-
        struct nls_table *nls_io, *nls_disk;
-
        struct mutex bitmap_lock;
-
        unsigned long flags;
-
        u16 blockoffset;
-
        int fs_div;
+       struct super_block *sb;
+       int work_queued;                /* non-zero delayed work is queued */
+       struct delayed_work mdb_work;   /* MDB flush delayed work */
+       spinlock_t work_lock;           /* protects mdb_work and work_queued */
 };
 
 #define HFS_FLG_BITMAP_DIRTY   0
@@ -226,6 +226,9 @@ extern int hfs_compare_dentry(const struct dentry *parent,
 extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
 extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
 
+/* super.c */
+extern void hfs_mark_mdb_dirty(struct super_block *sb);
+
 extern struct timezone sys_tz;
 
 /*
@@ -253,7 +256,7 @@ static inline const char *hfs_mdb_name(struct super_block *sb)
 static inline void hfs_bitmap_dirty(struct super_block *sb)
 {
        set_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags);
-       sb->s_dirt = 1;
+       hfs_mark_mdb_dirty(sb);
 }
 
 #define sb_bread512(sb, sec, data) ({                  \
index 761ec06354b4719df8731e098caaca14bbcf8127..ee1bc55677f1486c6f27a2549d8f6ce60c1581de 100644 (file)
@@ -220,7 +220,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode)
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
        set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-       sb->s_dirt = 1;
+       hfs_mark_mdb_dirty(sb);
 
        return inode;
 }
@@ -235,7 +235,7 @@ void hfs_delete_inode(struct inode *inode)
                if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
                        HFS_SB(sb)->root_dirs--;
                set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-               sb->s_dirt = 1;
+               hfs_mark_mdb_dirty(sb);
                return;
        }
        HFS_SB(sb)->file_count--;
@@ -248,7 +248,7 @@ void hfs_delete_inode(struct inode *inode)
                }
        }
        set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
-       sb->s_dirt = 1;
+       hfs_mark_mdb_dirty(sb);
 }
 
 void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
@@ -489,7 +489,7 @@ out:
 }
 
 static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
-                                     struct nameidata *nd)
+                                     unsigned int flags)
 {
        struct inode *inode = NULL;
        hfs_cat_rec rec;
@@ -644,13 +644,7 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
 
        /* sync the superblock to buffers */
        sb = inode->i_sb;
-       if (sb->s_dirt) {
-               lock_super(sb);
-               sb->s_dirt = 0;
-               if (!(sb->s_flags & MS_RDONLY))
-                       hfs_mdb_commit(sb);
-               unlock_super(sb);
-       }
+       flush_delayed_work_sync(&HFS_SB(sb)->mdb_work);
        /* .. finally sync the buffers to disk */
        err = sync_blockdev(sb->s_bdev);
        if (!ret)
index 1563d5ce57643e23ac08e3a7db02e0b336603c60..5fd51a5833ffb91facba871b74589bf8b9a6c087 100644 (file)
@@ -260,6 +260,10 @@ void hfs_mdb_commit(struct super_block *sb)
 {
        struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
 
+       if (sb->s_flags & MS_RDONLY)
+               return;
+
+       lock_buffer(HFS_SB(sb)->mdb_bh);
        if (test_and_clear_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags)) {
                /* These parameters may have been modified, so write them back */
                mdb->drLsMod = hfs_mtime();
@@ -283,9 +287,13 @@ void hfs_mdb_commit(struct super_block *sb)
                                     &mdb->drXTFlSize, NULL);
                hfs_inode_write_fork(HFS_SB(sb)->cat_tree->inode, mdb->drCTExtRec,
                                     &mdb->drCTFlSize, NULL);
+
+               lock_buffer(HFS_SB(sb)->alt_mdb_bh);
                memcpy(HFS_SB(sb)->alt_mdb, HFS_SB(sb)->mdb, HFS_SECTOR_SIZE);
                HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
                HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
+               unlock_buffer(HFS_SB(sb)->alt_mdb_bh);
+
                mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
                sync_dirty_buffer(HFS_SB(sb)->alt_mdb_bh);
        }
@@ -308,7 +316,11 @@ void hfs_mdb_commit(struct super_block *sb)
                                break;
                        }
                        len = min((int)sb->s_blocksize - off, size);
+
+                       lock_buffer(bh);
                        memcpy(bh->b_data + off, ptr, len);
+                       unlock_buffer(bh);
+
                        mark_buffer_dirty(bh);
                        brelse(bh);
                        block++;
@@ -317,6 +329,7 @@ void hfs_mdb_commit(struct super_block *sb)
                        size -= len;
                }
        }
+       unlock_buffer(HFS_SB(sb)->mdb_bh);
 }
 
 void hfs_mdb_close(struct super_block *sb)
index 7b4c537d6e136b42fba064de39b0c57703b5fec3..4eb873e0c07b137c0225f30b20fdf78bfb0c0006 100644 (file)
@@ -29,43 +29,9 @@ static struct kmem_cache *hfs_inode_cachep;
 
 MODULE_LICENSE("GPL");
 
-/*
- * hfs_write_super()
- *
- * Description:
- *   This function is called by the VFS only. When the filesystem
- *   is mounted r/w it updates the MDB on disk.
- * Input Variable(s):
- *   struct super_block *sb: Pointer to the hfs superblock
- * Output Variable(s):
- *   NONE
- * Returns:
- *   void
- * Preconditions:
- *   'sb' points to a "valid" (struct super_block).
- * Postconditions:
- *   The MDB is marked 'unsuccessfully unmounted' by clearing bit 8 of drAtrb
- *   (hfs_put_super() must set this flag!). Some MDB fields are updated
- *   and the MDB buffer is written to disk by calling hfs_mdb_commit().
- */
-static void hfs_write_super(struct super_block *sb)
-{
-       lock_super(sb);
-       sb->s_dirt = 0;
-
-       /* sync everything to the buffers */
-       if (!(sb->s_flags & MS_RDONLY))
-               hfs_mdb_commit(sb);
-       unlock_super(sb);
-}
-
 static int hfs_sync_fs(struct super_block *sb, int wait)
 {
-       lock_super(sb);
        hfs_mdb_commit(sb);
-       sb->s_dirt = 0;
-       unlock_super(sb);
-
        return 0;
 }
 
@@ -78,13 +44,44 @@ static int hfs_sync_fs(struct super_block *sb, int wait)
  */
 static void hfs_put_super(struct super_block *sb)
 {
-       if (sb->s_dirt)
-               hfs_write_super(sb);
+       cancel_delayed_work_sync(&HFS_SB(sb)->mdb_work);
        hfs_mdb_close(sb);
        /* release the MDB's resources */
        hfs_mdb_put(sb);
 }
 
+static void flush_mdb(struct work_struct *work)
+{
+       struct hfs_sb_info *sbi;
+       struct super_block *sb;
+
+       sbi = container_of(work, struct hfs_sb_info, mdb_work.work);
+       sb = sbi->sb;
+
+       spin_lock(&sbi->work_lock);
+       sbi->work_queued = 0;
+       spin_unlock(&sbi->work_lock);
+
+       hfs_mdb_commit(sb);
+}
+
+void hfs_mark_mdb_dirty(struct super_block *sb)
+{
+       struct hfs_sb_info *sbi = HFS_SB(sb);
+       unsigned long delay;
+
+       if (sb->s_flags & MS_RDONLY)
+               return;
+
+       spin_lock(&sbi->work_lock);
+       if (!sbi->work_queued) {
+               delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+               queue_delayed_work(system_long_wq, &sbi->mdb_work, delay);
+               sbi->work_queued = 1;
+       }
+       spin_unlock(&sbi->work_lock);
+}
+
 /*
  * hfs_statfs()
  *
@@ -184,7 +181,6 @@ static const struct super_operations hfs_super_operations = {
        .write_inode    = hfs_write_inode,
        .evict_inode    = hfs_evict_inode,
        .put_super      = hfs_put_super,
-       .write_super    = hfs_write_super,
        .sync_fs        = hfs_sync_fs,
        .statfs         = hfs_statfs,
        .remount_fs     = hfs_remount,
@@ -387,7 +383,10 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
        if (!sbi)
                return -ENOMEM;
 
+       sbi->sb = sb;
        sb->s_fs_info = sbi;
+       spin_lock_init(&sbi->work_lock);
+       INIT_DELAYED_WORK(&sbi->mdb_work, flush_mdb);
 
        res = -EINVAL;
        if (!parse_options((char *)data, sbi)) {
index 19cf291eb91f6325126121393ca2354204fb6c5f..91b91fd3a9013a08cc7d12d5e3934b09931b1a1e 100644 (file)
 
 /* dentry case-handling: just lowercase everything */
 
-static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
+static int hfs_revalidate_dentry(struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode;
        int diff;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = dentry->d_inode;
index 1cad80c789cb42e5ebada89cc294c9e07fde0d22..4cfbe2edd29692bfdb609c38c20b6d888349967f 100644 (file)
@@ -153,7 +153,7 @@ done:
        kunmap(page);
        *max = offset + (curr - pptr) * 32 + i - start;
        sbi->free_blocks -= *max;
-       sb->s_dirt = 1;
+       hfsplus_mark_mdb_dirty(sb);
        dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
 out:
        mutex_unlock(&sbi->alloc_mutex);
@@ -228,7 +228,7 @@ out:
        set_page_dirty(page);
        kunmap(page);
        sbi->free_blocks += len;
-       sb->s_dirt = 1;
+       hfsplus_mark_mdb_dirty(sb);
        mutex_unlock(&sbi->alloc_mutex);
 
        return 0;
index 26b53fb09f684404b2c488057f13c08ec8b2c0e2..6b9f921ef2fa178d75ed2e24d0e7a2a424fbf4d2 100644 (file)
@@ -25,7 +25,7 @@ static inline void hfsplus_instantiate(struct dentry *dentry,
 
 /* Find the entry inside dir named dentry->d_name */
 static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
-                                    struct nameidata *nd)
+                                    unsigned int flags)
 {
        struct inode *inode = NULL;
        struct hfs_find_data fd;
@@ -316,7 +316,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
        sbi->file_count++;
-       dst_dir->i_sb->s_dirt = 1;
+       hfsplus_mark_mdb_dirty(dst_dir->i_sb);
 out:
        mutex_unlock(&sbi->vh_mutex);
        return res;
@@ -465,7 +465,7 @@ out:
 }
 
 static int hfsplus_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                         struct nameidata *nd)
+                         bool excl)
 {
        return hfsplus_mknod(dir, dentry, mode, 0);
 }
index 4e75ac646fea3ac10643a657ae5276c7ee9d19c8..558dbb463a4e835632437a5bc427900c304a262f 100644 (file)
@@ -153,8 +153,11 @@ struct hfsplus_sb_info {
        gid_t gid;
 
        int part, session;
-
        unsigned long flags;
+
+       int work_queued;               /* non-zero delayed work is queued */
+       struct delayed_work sync_work; /* FS sync delayed work */
+       spinlock_t work_lock;          /* protects sync_work and work_queued */
 };
 
 #define HFSPLUS_SB_WRITEBACKUP 0
@@ -428,7 +431,7 @@ int hfsplus_show_options(struct seq_file *, struct dentry *);
 
 /* super.c */
 struct inode *hfsplus_iget(struct super_block *, unsigned long);
-int hfsplus_sync_fs(struct super_block *sb, int wait);
+void hfsplus_mark_mdb_dirty(struct super_block *sb);
 
 /* tables.c */
 extern u16 hfsplus_case_fold_table[];
index 82b69ee4dacce835559fa631c54115c11ba0f44e..3d8b4a675ba0d84a0b33d190b337eb1cc84a8fae 100644 (file)
@@ -168,7 +168,7 @@ const struct dentry_operations hfsplus_dentry_operations = {
 };
 
 static struct dentry *hfsplus_file_lookup(struct inode *dir,
-               struct dentry *dentry, struct nameidata *nd)
+               struct dentry *dentry, unsigned int flags)
 {
        struct hfs_find_data fd;
        struct super_block *sb = dir->i_sb;
@@ -431,7 +431,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
                sbi->file_count++;
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
-       sb->s_dirt = 1;
+       hfsplus_mark_mdb_dirty(sb);
 
        return inode;
 }
@@ -442,7 +442,7 @@ void hfsplus_delete_inode(struct inode *inode)
 
        if (S_ISDIR(inode->i_mode)) {
                HFSPLUS_SB(sb)->folder_count--;
-               sb->s_dirt = 1;
+               hfsplus_mark_mdb_dirty(sb);
                return;
        }
        HFSPLUS_SB(sb)->file_count--;
@@ -455,7 +455,7 @@ void hfsplus_delete_inode(struct inode *inode)
                inode->i_size = 0;
                hfsplus_file_truncate(inode);
        }
-       sb->s_dirt = 1;
+       hfsplus_mark_mdb_dirty(sb);
 }
 
 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
index a9bca4b8768be786346ec1c832ed73e2c3699df3..47333209801378c5cbd5baef0c948c1767a4fa2a 100644 (file)
@@ -124,7 +124,7 @@ static int hfsplus_system_write_inode(struct inode *inode)
 
        if (fork->total_size != cpu_to_be64(inode->i_size)) {
                set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
-               inode->i_sb->s_dirt = 1;
+               hfsplus_mark_mdb_dirty(inode->i_sb);
        }
        hfsplus_inode_write_fork(inode, fork);
        if (tree)
@@ -161,7 +161,7 @@ static void hfsplus_evict_inode(struct inode *inode)
        }
 }
 
-int hfsplus_sync_fs(struct super_block *sb, int wait)
+static int hfsplus_sync_fs(struct super_block *sb, int wait)
 {
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct hfsplus_vh *vhdr = sbi->s_vhdr;
@@ -171,9 +171,7 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
        if (!wait)
                return 0;
 
-       dprint(DBG_SUPER, "hfsplus_write_super\n");
-
-       sb->s_dirt = 0;
+       dprint(DBG_SUPER, "hfsplus_sync_fs\n");
 
        /*
         * Explicitly write out the special metadata inodes.
@@ -226,12 +224,34 @@ out:
        return error;
 }
 
-static void hfsplus_write_super(struct super_block *sb)
+static void delayed_sync_fs(struct work_struct *work)
 {
-       if (!(sb->s_flags & MS_RDONLY))
-               hfsplus_sync_fs(sb, 1);
-       else
-               sb->s_dirt = 0;
+       struct hfsplus_sb_info *sbi;
+
+       sbi = container_of(work, struct hfsplus_sb_info, sync_work.work);
+
+       spin_lock(&sbi->work_lock);
+       sbi->work_queued = 0;
+       spin_unlock(&sbi->work_lock);
+
+       hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
+}
+
+void hfsplus_mark_mdb_dirty(struct super_block *sb)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       unsigned long delay;
+
+       if (sb->s_flags & MS_RDONLY)
+               return;
+
+       spin_lock(&sbi->work_lock);
+       if (!sbi->work_queued) {
+               delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+               queue_delayed_work(system_long_wq, &sbi->sync_work, delay);
+               sbi->work_queued = 1;
+       }
+       spin_unlock(&sbi->work_lock);
 }
 
 static void hfsplus_put_super(struct super_block *sb)
@@ -240,8 +260,7 @@ static void hfsplus_put_super(struct super_block *sb)
 
        dprint(DBG_SUPER, "hfsplus_put_super\n");
 
-       if (!sb->s_fs_info)
-               return;
+       cancel_delayed_work_sync(&sbi->sync_work);
 
        if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
                struct hfsplus_vh *vhdr = sbi->s_vhdr;
@@ -328,7 +347,6 @@ static const struct super_operations hfsplus_sops = {
        .write_inode    = hfsplus_write_inode,
        .evict_inode    = hfsplus_evict_inode,
        .put_super      = hfsplus_put_super,
-       .write_super    = hfsplus_write_super,
        .sync_fs        = hfsplus_sync_fs,
        .statfs         = hfsplus_statfs,
        .remount_fs     = hfsplus_remount,
@@ -355,6 +373,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_fs_info = sbi;
        mutex_init(&sbi->alloc_mutex);
        mutex_init(&sbi->vh_mutex);
+       spin_lock_init(&sbi->work_lock);
+       INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);
        hfsplus_fill_defaults(sbi);
 
        err = -EINVAL;
index 2afa5bbccf9baf9cc4389d88940cb21516bf8bb8..124146543aa76ec87187955cf237f6a04e441ad4 100644 (file)
@@ -553,7 +553,7 @@ static int read_name(struct inode *ino, char *name)
 }
 
 int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                 struct nameidata *nd)
+                 bool excl)
 {
        struct inode *inode;
        char *name;
@@ -595,7 +595,7 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
 }
 
 struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
-                            struct nameidata *nd)
+                            unsigned int flags)
 {
        struct inode *inode;
        char *name;
index b8472f803f4e54ea5039b85ac36cfdf33a48925b..78e12b2e0ea2c487dd09b89794e5e3bdb666152b 100644 (file)
@@ -189,7 +189,7 @@ out:
  *           to tell read_inode to read fnode or not.
  */
 
-struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        const unsigned char *name = dentry->d_name.name;
        unsigned len = dentry->d_name.len;
index c07ef1f1ced60a0cf295772a218575d9c78e58d1..ac1ead194db5ebf2ea8d5f1ef2102033615d08a9 100644 (file)
@@ -220,7 +220,7 @@ extern const struct dentry_operations hpfs_dentry_operations;
 
 /* dir.c */
 
-struct dentry *hpfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+struct dentry *hpfs_lookup(struct inode *, struct dentry *, unsigned int);
 extern const struct file_operations hpfs_dir_ops;
 
 /* dnode.c */
index 9083ef8af58c162f7fd207f7ef37263b1f35de4f..bc9082482f6841c21a0bb520d4333fae14efcb9a 100644 (file)
@@ -115,7 +115,7 @@ bail:
        return err;
 }
 
-static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
        const unsigned char *name = dentry->d_name.name;
        unsigned len = dentry->d_name.len;
index d4f93b52cec512723447fb1390a9c9b6cca8b45f..c1dffe47fde212b75daa69a0860255ee39b29285 100644 (file)
@@ -138,7 +138,7 @@ static int file_removed(struct dentry *dentry, const char *file)
 }
 
 static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        struct dentry *proc_dentry, *parent;
        struct qstr *name = &dentry->d_name;
@@ -420,8 +420,7 @@ static int hppfs_open(struct inode *inode, struct file *file)
 {
        const struct cred *cred = file->f_cred;
        struct hppfs_private *data;
-       struct vfsmount *proc_mnt;
-       struct dentry *proc_dentry;
+       struct path path;
        char *host_file;
        int err, fd, type, filter;
 
@@ -434,12 +433,11 @@ static int hppfs_open(struct inode *inode, struct file *file)
        if (host_file == NULL)
                goto out_free2;
 
-       proc_dentry = HPPFS_I(inode)->proc_dentry;
-       proc_mnt = inode->i_sb->s_fs_info;
+       path.mnt = inode->i_sb->s_fs_info;
+       path.dentry = HPPFS_I(inode)->proc_dentry;
 
        /* XXX This isn't closed anywhere */
-       data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
-                                     file_mode(file->f_mode), cred);
+       data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred);
        err = PTR_ERR(data->proc_file);
        if (IS_ERR(data->proc_file))
                goto out_free1;
@@ -484,8 +482,7 @@ static int hppfs_dir_open(struct inode *inode, struct file *file)
 {
        const struct cred *cred = file->f_cred;
        struct hppfs_private *data;
-       struct vfsmount *proc_mnt;
-       struct dentry *proc_dentry;
+       struct path path;
        int err;
 
        err = -ENOMEM;
@@ -493,10 +490,9 @@ static int hppfs_dir_open(struct inode *inode, struct file *file)
        if (data == NULL)
                goto out;
 
-       proc_dentry = HPPFS_I(inode)->proc_dentry;
-       proc_mnt = inode->i_sb->s_fs_info;
-       data->proc_file = dentry_open(dget(proc_dentry), mntget(proc_mnt),
-                                     file_mode(file->f_mode), cred);
+       path.mnt = inode->i_sb->s_fs_info;
+       path.dentry = HPPFS_I(inode)->proc_dentry;
+       data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred);
        err = PTR_ERR(data->proc_file);
        if (IS_ERR(data->proc_file))
                goto out_free;
index cc9281b6c62893a94cedcb36128dcae427861fcd..e13e9bdb0bf57f2cdfe03fc1ad013826e1668d41 100644 (file)
@@ -565,7 +565,7 @@ static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mod
        return retval;
 }
 
-static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
        return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0);
 }
index c99163b1b31036ef68974c0c5dbc192f8f73f4da..775cbabd4fa5f3fe3840277a4f0aac4456f02396 100644 (file)
@@ -182,7 +182,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        }
        inode->i_private = NULL;
        inode->i_mapping = mapping;
-       INIT_LIST_HEAD(&inode->i_dentry);       /* buggered by rcu freeing */
+       INIT_HLIST_HEAD(&inode->i_dentry);      /* buggered by rcu freeing */
 #ifdef CONFIG_FS_POSIX_ACL
        inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
 #endif
index 18bc216ea09d95ecff126ef96987ff786b5cbcb1..a6fd56c68b1164928d380fdc787a988107c15a55 100644 (file)
@@ -41,6 +41,11 @@ static inline int __sync_blockdev(struct block_device *bdev, int wait)
  */
 extern void __init chrdev_init(void);
 
+/*
+ * namei.c
+ */
+extern int __inode_permission(struct inode *, int);
+
 /*
  * namespace.c
  */
@@ -50,8 +55,6 @@ extern int copy_mount_string(const void __user *, char **);
 extern struct vfsmount *lookup_mnt(struct path *);
 extern int finish_automount(struct vfsmount *, struct path *);
 
-extern void mnt_make_longterm(struct vfsmount *);
-extern void mnt_make_shortterm(struct vfsmount *);
 extern int sb_prepare_remount_readonly(struct super_block *);
 
 extern void __init mnt_init(void);
@@ -84,9 +87,6 @@ extern struct super_block *user_get_super(dev_t);
 /*
  * open.c
  */
-struct nameidata;
-extern struct file *nameidata_to_filp(struct nameidata *);
-extern void release_open_intent(struct nameidata *);
 struct open_flags {
        int open_flag;
        umode_t mode;
index 0e73f63d92745d244a7007b3d1b367784d467c58..3620ad1ea9bcfc31cf2814ad98df9896cbd8bba9 100644 (file)
@@ -114,7 +114,7 @@ extern int isofs_name_translate(struct iso_directory_record *, char *, struct in
 int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
 int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
-extern struct dentry *isofs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int flags);
 extern struct buffer_head *isofs_bread(struct inode *, sector_t);
 extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
 
index 1e2946f2a69e5ac6dd17924f124459b318439eb8..c167028844ed539fca2b25931ccfb51a8d32d962 100644 (file)
@@ -163,7 +163,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
        return 0;
 }
 
-struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        int found;
        unsigned long uninitialized_var(block);
index b56018896d5e398b3f5bce94776db8dd0cf9de37..ad7774d3209575b0bf47d010dad56043412d2ac8 100644 (file)
@@ -25,9 +25,9 @@
 static int jffs2_readdir (struct file *, void *, filldir_t);
 
 static int jffs2_create (struct inode *,struct dentry *,umode_t,
-                        struct nameidata *);
+                        bool);
 static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
-                                   struct nameidata *);
+                                   unsigned int);
 static int jffs2_link (struct dentry *,struct inode *,struct dentry *);
 static int jffs2_unlink (struct inode *,struct dentry *);
 static int jffs2_symlink (struct inode *,struct dentry *,const char *);
@@ -74,7 +74,7 @@ const struct inode_operations jffs2_dir_inode_operations =
    nice and simple
 */
 static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        struct jffs2_inode_info *dir_f;
        struct jffs2_full_dirent *fd = NULL, *fd_list;
@@ -175,7 +175,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
 
 static int jffs2_create(struct inode *dir_i, struct dentry *dentry,
-                       umode_t mode, struct nameidata *nd)
+                       umode_t mode, bool excl)
 {
        struct jffs2_raw_inode *ri;
        struct jffs2_inode_info *f, *dir_f;
@@ -226,8 +226,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry,
                  __func__, inode->i_ino, inode->i_mode, inode->i_nlink,
                  f->inocache->pino_nlink, inode->i_mapping->nrpages);
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        return 0;
 
  fail:
@@ -446,8 +446,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        mutex_unlock(&dir_f->sem);
        jffs2_complete_reservation(c);
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        return 0;
 
  fail:
@@ -591,8 +591,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode
        mutex_unlock(&dir_f->sem);
        jffs2_complete_reservation(c);
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        return 0;
 
  fail:
@@ -766,8 +766,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode
        mutex_unlock(&dir_f->sem);
        jffs2_complete_reservation(c);
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        return 0;
 
  fail:
index 07c91ca6017db03d404362e5e763fdbf90fdc2ef..3b91a7ad60862008f50c67526b7854f938aadc19 100644 (file)
@@ -73,7 +73,7 @@ static inline void free_ea_wmap(struct inode *inode)
  *
  */
 static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        int rc = 0;
        tid_t tid;              /* transaction id */
@@ -176,8 +176,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
                unlock_new_inode(ip);
                iput(ip);
        } else {
-               d_instantiate(dentry, ip);
                unlock_new_inode(ip);
+               d_instantiate(dentry, ip);
        }
 
       out2:
@@ -309,8 +309,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
                unlock_new_inode(ip);
                iput(ip);
        } else {
-               d_instantiate(dentry, ip);
                unlock_new_inode(ip);
+               d_instantiate(dentry, ip);
        }
 
       out2:
@@ -1043,8 +1043,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
                unlock_new_inode(ip);
                iput(ip);
        } else {
-               d_instantiate(dentry, ip);
                unlock_new_inode(ip);
+               d_instantiate(dentry, ip);
        }
 
       out2:
@@ -1424,8 +1424,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
                unlock_new_inode(ip);
                iput(ip);
        } else {
-               d_instantiate(dentry, ip);
                unlock_new_inode(ip);
+               d_instantiate(dentry, ip);
        }
 
       out1:
@@ -1436,7 +1436,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
        return rc;
 }
 
-static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
 {
        struct btstack btstack;
        ino_t inum;
@@ -1570,7 +1570,7 @@ out:
        return result;
 }
 
-static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags)
 {
        /*
         * This is not negative dentry. Always valid.
@@ -1589,7 +1589,7 @@ static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
         * This may be nfsd (or something), anyway, we can't see the
         * intent of this. So, since this can be for creation, drop it.
         */
-       if (!nd)
+       if (!flags)
                return 0;
 
        /*
@@ -1597,7 +1597,7 @@ static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
         * case sensitive name which is specified by user if this is
         * for creation.
         */
-       if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
+       if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
                return 0;
        return 1;
 }
index 4a82950f412f8c274007f574e91b9ee59766061a..c55c7452d2857c1f0f59042f5b6ffd1de9eba8b6 100644 (file)
@@ -601,6 +601,11 @@ static int jfs_sync_fs(struct super_block *sb, int wait)
 
        /* log == NULL indicates read-only mount */
        if (log) {
+               /*
+                * Write quota structures to quota file, sync_blockdev() will
+                * write them to disk later
+                */
+               dquot_writeback_dquots(sb, -1);
                jfs_flush_journal(log, wait);
                jfs_syncpt(log, 0);
        }
index f86ec27a4230a6cd23f6d020c53217cd30a060f1..a74cb1725ac694adf25be38ad2266afc0f382059 100644 (file)
@@ -53,7 +53,7 @@ static int simple_delete_dentry(const struct dentry *dentry)
  * Lookup the data. This is trivial - if the dentry didn't already
  * exist, we know it is negative.  Set d_op to delete negative dentries.
  */
-struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        static const struct dentry_operations simple_dentry_operations = {
                .d_delete = simple_delete_dentry,
@@ -222,15 +222,15 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
        const struct super_operations *ops,
        const struct dentry_operations *dops, unsigned long magic)
 {
-       struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
+       struct super_block *s;
        struct dentry *dentry;
        struct inode *root;
        struct qstr d_name = QSTR_INIT(name, strlen(name));
 
+       s = sget(fs_type, NULL, set_anon_super, MS_NOUSER, NULL);
        if (IS_ERR(s))
                return ERR_CAST(s);
 
-       s->s_flags = MS_NOUSER;
        s->s_maxbytes = MAX_LFS_FILESIZE;
        s->s_blocksize = PAGE_SIZE;
        s->s_blocksize_bits = PAGE_SHIFT;
index 814c51d0de4739e4b89e9091e00c17f284c0e2ba..82c353304f9eeccab27b01b86379441df323deeb 100644 (file)
@@ -308,7 +308,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock,
        return 0;
 }
 
-static int assign_type(struct file_lock *fl, int type)
+static int assign_type(struct file_lock *fl, long type)
 {
        switch (type) {
        case F_RDLCK:
@@ -445,7 +445,7 @@ static const struct lock_manager_operations lease_manager_ops = {
 /*
  * Initialize a lease, use the default lock manager operations
  */
-static int lease_init(struct file *filp, int type, struct file_lock *fl)
+static int lease_init(struct file *filp, long type, struct file_lock *fl)
  {
        if (assign_type(fl, type) != 0)
                return -EINVAL;
@@ -463,7 +463,7 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl)
 }
 
 /* Allocate a file_lock initialised to this type of lease */
-static struct file_lock *lease_alloc(struct file *filp, int type)
+static struct file_lock *lease_alloc(struct file *filp, long type)
 {
        struct file_lock *fl = locks_alloc_lock();
        int error = -ENOMEM;
@@ -1465,7 +1465,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
        case F_WRLCK:
                return generic_add_lease(filp, arg, flp);
        default:
-               BUG();
+               return -EINVAL;
        }
 }
 EXPORT_SYMBOL(generic_setlease);
index bea5d1b9954ba771b76829acc2e1d6a92162310a..26e4a941532fb62dc18338a08bd313d9ccb4445b 100644 (file)
@@ -349,7 +349,7 @@ static void logfs_set_name(struct logfs_disk_dentry *dd, struct qstr *name)
 }
 
 static struct dentry *logfs_lookup(struct inode *dir, struct dentry *dentry,
-               struct nameidata *nd)
+               unsigned int flags)
 {
        struct page *page;
        struct logfs_disk_dentry *dd;
@@ -502,7 +502,7 @@ static int logfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 }
 
 static int logfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        struct inode *inode;
 
index 97bca623d893a8345323739add9a4178da72ec9a..345c24b8a6f86965b39d7dd017fb294908ddd8d0 100644 (file)
@@ -519,7 +519,7 @@ static struct dentry *logfs_get_sb_device(struct logfs_super *super,
        log_super("LogFS: Start mount %x\n", mount_count++);
 
        err = -EINVAL;
-       sb = sget(type, logfs_sb_test, logfs_sb_set, super);
+       sb = sget(type, logfs_sb_test, logfs_sb_set, flags | MS_NOATIME, super);
        if (IS_ERR(sb)) {
                super->s_devops->put_device(super);
                kfree(super);
@@ -542,7 +542,6 @@ static struct dentry *logfs_get_sb_device(struct logfs_super *super,
        sb->s_maxbytes  = (1ull << 43) - 1;
        sb->s_max_links = LOGFS_LINK_MAX;
        sb->s_op        = &logfs_super_operations;
-       sb->s_flags     = flags | MS_NOATIME;
 
        err = logfs_read_sb(sb, sb->s_flags & MS_RDONLY);
        if (err)
index 2d0ee17863051d4c31e747f451e4565d657cc6d9..0db73d9dd66845d289f6f1a58e1960ecc1ee3e74 100644 (file)
@@ -18,7 +18,7 @@ static int add_nondir(struct dentry *dentry, struct inode *inode)
        return err;
 }
 
-static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode * inode = NULL;
        ino_t ino;
@@ -55,7 +55,7 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode,
 }
 
 static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        return minix_mknod(dir, dentry, mode, 0);
 }
index 4ef36d93e5a241822e10c21f93dc72d7137d32ec..4f291f9de641ea2aca94f609daa7e865ae71fd58 100644 (file)
@@ -22,7 +22,6 @@ struct mount {
        struct vfsmount mnt;
 #ifdef CONFIG_SMP
        struct mnt_pcp __percpu *mnt_pcp;
-       atomic_t mnt_longterm;          /* how many of the refs are longterm */
 #else
        int mnt_count;
        int mnt_writers;
@@ -49,6 +48,8 @@ struct mount {
        int mnt_ghosts;
 };
 
+#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
+
 static inline struct mount *real_mount(struct vfsmount *mnt)
 {
        return container_of(mnt, struct mount, mnt);
@@ -59,6 +60,12 @@ static inline int mnt_has_parent(struct mount *mnt)
        return mnt != mnt->mnt_parent;
 }
 
+static inline int is_mounted(struct vfsmount *mnt)
+{
+       /* neither detached nor internal? */
+       return !IS_ERR_OR_NULL(real_mount(mnt));
+}
+
 extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
 
 static inline void get_mnt_ns(struct mnt_namespace *ns)
@@ -67,10 +74,12 @@ static inline void get_mnt_ns(struct mnt_namespace *ns)
 }
 
 struct proc_mounts {
-       struct seq_file m; /* must be the first element */
+       struct seq_file m;
        struct mnt_namespace *ns;
        struct path root;
        int (*show)(struct seq_file *, struct vfsmount *);
 };
 
+#define proc_mounts(p) (container_of((p), struct proc_mounts, m))
+
 extern const struct seq_operations mounts_op;
index 7d694194024ac4d2459e7cc3d60014bdff64e3ba..2ccc35c4dc24d95e2a5c1bf5528528fa6f22827d 100644 (file)
@@ -315,31 +315,22 @@ static inline int do_inode_permission(struct inode *inode, int mask)
 }
 
 /**
- * inode_permission  -  check for access rights to a given inode
- * @inode:     inode to check permission on
- * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
+ * __inode_permission - Check for access rights to a given inode
+ * @inode: Inode to check permission on
+ * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
  *
- * Used to check for read/write/execute permissions on an inode.
- * We use "fsuid" for this, letting us set arbitrary permissions
- * for filesystem access without changing the "normal" uids which
- * are used for other things.
+ * Check for read/write/execute permissions on an inode.
  *
  * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
+ *
+ * This does not check for a read-only file system.  You probably want
+ * inode_permission().
  */
-int inode_permission(struct inode *inode, int mask)
+int __inode_permission(struct inode *inode, int mask)
 {
        int retval;
 
        if (unlikely(mask & MAY_WRITE)) {
-               umode_t mode = inode->i_mode;
-
-               /*
-                * Nobody gets write access to a read-only fs.
-                */
-               if (IS_RDONLY(inode) &&
-                   (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
-                       return -EROFS;
-
                /*
                 * Nobody gets write access to an immutable file.
                 */
@@ -358,6 +349,47 @@ int inode_permission(struct inode *inode, int mask)
        return security_inode_permission(inode, mask);
 }
 
+/**
+ * sb_permission - Check superblock-level permissions
+ * @sb: Superblock of inode to check permission on
+ * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Separate out file-system wide checks from inode-specific permission checks.
+ */
+static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
+{
+       if (unlikely(mask & MAY_WRITE)) {
+               umode_t mode = inode->i_mode;
+
+               /* Nobody gets write access to a read-only fs. */
+               if ((sb->s_flags & MS_RDONLY) &&
+                   (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
+                       return -EROFS;
+       }
+       return 0;
+}
+
+/**
+ * inode_permission - Check for access rights to a given inode
+ * @inode: Inode to check permission on
+ * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
+ *
+ * Check for read/write/execute permissions on an inode.  We use fs[ug]id for
+ * this, letting us set arbitrary permissions for filesystem access without
+ * changing the "normal" UIDs which are used for other things.
+ *
+ * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
+ */
+int inode_permission(struct inode *inode, int mask)
+{
+       int retval;
+
+       retval = sb_permission(inode->i_sb, inode, mask);
+       if (retval)
+               return retval;
+       return __inode_permission(inode, mask);
+}
+
 /**
  * path_get - get a reference to a path
  * @path: path to get the reference to
@@ -395,6 +427,18 @@ EXPORT_SYMBOL(path_put);
  * to restart the path walk from the beginning in ref-walk mode.
  */
 
+static inline void lock_rcu_walk(void)
+{
+       br_read_lock(&vfsmount_lock);
+       rcu_read_lock();
+}
+
+static inline void unlock_rcu_walk(void)
+{
+       rcu_read_unlock();
+       br_read_unlock(&vfsmount_lock);
+}
+
 /**
  * unlazy_walk - try to switch to ref-walk mode.
  * @nd: nameidata pathwalk data
@@ -448,8 +492,7 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
        }
        mntget(nd->path.mnt);
 
-       rcu_read_unlock();
-       br_read_unlock(&vfsmount_lock);
+       unlock_rcu_walk();
        nd->flags &= ~LOOKUP_RCU;
        return 0;
 
@@ -463,25 +506,9 @@ err_root:
        return -ECHILD;
 }
 
-/**
- * release_open_intent - free up open intent resources
- * @nd: pointer to nameidata
- */
-void release_open_intent(struct nameidata *nd)
+static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
 {
-       struct file *file = nd->intent.open.file;
-
-       if (file && !IS_ERR(file)) {
-               if (file->f_path.dentry == NULL)
-                       put_filp(file);
-               else
-                       fput(file);
-       }
-}
-
-static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
-       return dentry->d_op->d_revalidate(dentry, nd);
+       return dentry->d_op->d_revalidate(dentry, flags);
 }
 
 /**
@@ -506,15 +533,13 @@ static int complete_walk(struct nameidata *nd)
                spin_lock(&dentry->d_lock);
                if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) {
                        spin_unlock(&dentry->d_lock);
-                       rcu_read_unlock();
-                       br_read_unlock(&vfsmount_lock);
+                       unlock_rcu_walk();
                        return -ECHILD;
                }
                BUG_ON(nd->inode != dentry->d_inode);
                spin_unlock(&dentry->d_lock);
                mntget(nd->path.mnt);
-               rcu_read_unlock();
-               br_read_unlock(&vfsmount_lock);
+               unlock_rcu_walk();
        }
 
        if (likely(!(nd->flags & LOOKUP_JUMPED)))
@@ -527,7 +552,7 @@ static int complete_walk(struct nameidata *nd)
                return 0;
 
        /* Note: we do not d_invalidate() */
-       status = d_revalidate(dentry, nd);
+       status = d_revalidate(dentry, nd->flags);
        if (status > 0)
                return 0;
 
@@ -602,10 +627,25 @@ static inline void path_to_nameidata(const struct path *path,
        nd->path.dentry = path->dentry;
 }
 
+/*
+ * Helper to directly jump to a known parsed path from ->follow_link,
+ * caller must have taken a reference to path beforehand.
+ */
+void nd_jump_link(struct nameidata *nd, struct path *path)
+{
+       path_put(&nd->path);
+
+       nd->path = *path;
+       nd->inode = nd->path.dentry->d_inode;
+       nd->flags |= LOOKUP_JUMPED;
+
+       BUG_ON(nd->inode->i_op->follow_link);
+}
+
 static inline void put_link(struct nameidata *nd, struct path *link, void *cookie)
 {
        struct inode *inode = link->dentry->d_inode;
-       if (!IS_ERR(cookie) && inode->i_op->put_link)
+       if (inode->i_op->put_link)
                inode->i_op->put_link(link->dentry, nd, cookie);
        path_put(link);
 }
@@ -613,19 +653,19 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
 static __always_inline int
 follow_link(struct path *link, struct nameidata *nd, void **p)
 {
-       int error;
        struct dentry *dentry = link->dentry;
+       int error;
+       char *s;
 
        BUG_ON(nd->flags & LOOKUP_RCU);
 
        if (link->mnt == nd->path.mnt)
                mntget(link->mnt);
 
-       if (unlikely(current->total_link_count >= 40)) {
-               *p = ERR_PTR(-ELOOP); /* no ->put_link(), please */
-               path_put(&nd->path);
-               return -ELOOP;
-       }
+       error = -ELOOP;
+       if (unlikely(current->total_link_count >= 40))
+               goto out_put_nd_path;
+
        cond_resched();
        current->total_link_count++;
 
@@ -633,30 +673,28 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
        nd_set_link(nd, NULL);
 
        error = security_inode_follow_link(link->dentry, nd);
-       if (error) {
-               *p = ERR_PTR(error); /* no ->put_link(), please */
-               path_put(&nd->path);
-               return error;
-       }
+       if (error)
+               goto out_put_nd_path;
 
        nd->last_type = LAST_BIND;
        *p = dentry->d_inode->i_op->follow_link(dentry, nd);
        error = PTR_ERR(*p);
-       if (!IS_ERR(*p)) {
-               char *s = nd_get_link(nd);
-               error = 0;
-               if (s)
-                       error = __vfs_follow_link(nd, s);
-               else if (nd->last_type == LAST_BIND) {
-                       nd->flags |= LOOKUP_JUMPED;
-                       nd->inode = nd->path.dentry->d_inode;
-                       if (nd->inode->i_op->follow_link) {
-                               /* stepped on a _really_ weird one */
-                               path_put(&nd->path);
-                               error = -ELOOP;
-                       }
-               }
+       if (IS_ERR(*p))
+               goto out_put_nd_path;
+
+       error = 0;
+       s = nd_get_link(nd);
+       if (s) {
+               error = __vfs_follow_link(nd, s);
+               if (unlikely(error))
+                       put_link(nd, link, *p);
        }
+
+       return error;
+
+out_put_nd_path:
+       path_put(&nd->path);
+       path_put(link);
        return error;
 }
 
@@ -675,6 +713,16 @@ static int follow_up_rcu(struct path *path)
        return 1;
 }
 
+/*
+ * follow_up - Find the mountpoint of path's vfsmount
+ *
+ * Given a path, find the mountpoint of its source file system.
+ * Replace @path with the path of the mountpoint in the parent mount.
+ * Up is towards /.
+ *
+ * Return 1 if we went up a level and 0 if we were already at the
+ * root.
+ */
 int follow_up(struct path *path)
 {
        struct mount *mnt = real_mount(path->mnt);
@@ -683,7 +731,7 @@ int follow_up(struct path *path)
 
        br_read_lock(&vfsmount_lock);
        parent = mnt->mnt_parent;
-       if (&parent->mnt == path->mnt) {
+       if (parent == mnt) {
                br_read_unlock(&vfsmount_lock);
                return 0;
        }
@@ -946,8 +994,7 @@ failed:
        nd->flags &= ~LOOKUP_RCU;
        if (!(nd->flags & LOOKUP_ROOT))
                nd->root.mnt = NULL;
-       rcu_read_unlock();
-       br_read_unlock(&vfsmount_lock);
+       unlock_rcu_walk();
        return -ECHILD;
 }
 
@@ -1048,7 +1095,7 @@ static void follow_dotdot(struct nameidata *nd)
  * dir->d_inode->i_mutex must be held
  */
 static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
-                                   struct nameidata *nd, bool *need_lookup)
+                                   unsigned int flags, bool *need_lookup)
 {
        struct dentry *dentry;
        int error;
@@ -1059,7 +1106,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
                if (d_need_lookup(dentry)) {
                        *need_lookup = true;
                } else if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
-                       error = d_revalidate(dentry, nd);
+                       error = d_revalidate(dentry, flags);
                        if (unlikely(error <= 0)) {
                                if (error < 0) {
                                        dput(dentry);
@@ -1089,7 +1136,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
  * dir->d_inode->i_mutex must be held
  */
 static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
-                                 struct nameidata *nd)
+                                 unsigned int flags)
 {
        struct dentry *old;
 
@@ -1099,7 +1146,7 @@ static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
                return ERR_PTR(-ENOENT);
        }
 
-       old = dir->i_op->lookup(dir, dentry, nd);
+       old = dir->i_op->lookup(dir, dentry, flags);
        if (unlikely(old)) {
                dput(dentry);
                dentry = old;
@@ -1108,16 +1155,16 @@ static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry,
 }
 
 static struct dentry *__lookup_hash(struct qstr *name,
-               struct dentry *base, struct nameidata *nd)
+               struct dentry *base, unsigned int flags)
 {
        bool need_lookup;
        struct dentry *dentry;
 
-       dentry = lookup_dcache(name, base, nd, &need_lookup);
+       dentry = lookup_dcache(name, base, flags, &need_lookup);
        if (!need_lookup)
                return dentry;
 
-       return lookup_real(base->d_inode, dentry, nd);
+       return lookup_real(base->d_inode, dentry, flags);
 }
 
 /*
@@ -1167,7 +1214,7 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name,
                if (unlikely(d_need_lookup(dentry)))
                        goto unlazy;
                if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
-                       status = d_revalidate(dentry, nd);
+                       status = d_revalidate(dentry, nd->flags);
                        if (unlikely(status <= 0)) {
                                if (status != -ECHILD)
                                        need_reval = 0;
@@ -1197,7 +1244,7 @@ unlazy:
        }
 
        if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
-               status = d_revalidate(dentry, nd);
+               status = d_revalidate(dentry, nd->flags);
        if (unlikely(status <= 0)) {
                if (status < 0) {
                        dput(dentry);
@@ -1236,7 +1283,7 @@ static int lookup_slow(struct nameidata *nd, struct qstr *name,
        BUG_ON(nd->inode != parent->d_inode);
 
        mutex_lock(&parent->d_inode->i_mutex);
-       dentry = __lookup_hash(name, parent, nd);
+       dentry = __lookup_hash(name, parent, nd->flags);
        mutex_unlock(&parent->d_inode->i_mutex);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
@@ -1284,8 +1331,7 @@ static void terminate_walk(struct nameidata *nd)
                nd->flags &= ~LOOKUP_RCU;
                if (!(nd->flags & LOOKUP_ROOT))
                        nd->root.mnt = NULL;
-               rcu_read_unlock();
-               br_read_unlock(&vfsmount_lock);
+               unlock_rcu_walk();
        }
 }
 
@@ -1383,9 +1429,10 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
                void *cookie;
 
                res = follow_link(&link, nd, &cookie);
-               if (!res)
-                       res = walk_component(nd, path, &nd->last,
-                                            nd->last_type, LOOKUP_FOLLOW);
+               if (res)
+                       break;
+               res = walk_component(nd, path, &nd->last,
+                                    nd->last_type, LOOKUP_FOLLOW);
                put_link(nd, &link, cookie);
        } while (res > 0);
 
@@ -1651,8 +1698,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                nd->path = nd->root;
                nd->inode = inode;
                if (flags & LOOKUP_RCU) {
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
                } else {
                        path_get(&nd->path);
@@ -1664,8 +1710,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 
        if (*name=='/') {
                if (flags & LOOKUP_RCU) {
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
                        set_root_rcu(nd);
                } else {
                        set_root(nd);
@@ -1677,8 +1722,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                        struct fs_struct *fs = current->fs;
                        unsigned seq;
 
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
 
                        do {
                                seq = read_seqcount_begin(&fs->seq);
@@ -1713,8 +1757,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                        if (fput_needed)
                                *fp = file;
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
-                       br_read_lock(&vfsmount_lock);
-                       rcu_read_lock();
+                       lock_rcu_walk();
                } else {
                        path_get(&file->f_path);
                        fput_light(file, fput_needed);
@@ -1777,8 +1820,9 @@ static int path_lookupat(int dfd, const char *name,
                        struct path link = path;
                        nd->flags |= LOOKUP_PARENT;
                        err = follow_link(&link, nd, &cookie);
-                       if (!err)
-                               err = lookup_last(nd, &path);
+                       if (err)
+                               break;
+                       err = lookup_last(nd, &path);
                        put_link(nd, &link, cookie);
                }
        }
@@ -1821,9 +1865,27 @@ static int do_path_lookup(int dfd, const char *name,
        return retval;
 }
 
-int kern_path_parent(const char *name, struct nameidata *nd)
+/* does lookup, returns the object with parent locked */
+struct dentry *kern_path_locked(const char *name, struct path *path)
 {
-       return do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, nd);
+       struct nameidata nd;
+       struct dentry *d;
+       int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd);
+       if (err)
+               return ERR_PTR(err);
+       if (nd.last_type != LAST_NORM) {
+               path_put(&nd.path);
+               return ERR_PTR(-EINVAL);
+       }
+       mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+       d = __lookup_hash(&nd.last, nd.path.dentry, 0);
+       if (IS_ERR(d)) {
+               mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+               path_put(&nd.path);
+               return d;
+       }
+       *path = nd.path;
+       return d;
 }
 
 int kern_path(const char *name, unsigned int flags, struct path *path)
@@ -1866,7 +1928,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
  */
 static struct dentry *lookup_hash(struct nameidata *nd)
 {
-       return __lookup_hash(&nd->last, nd->path.dentry, nd);
+       return __lookup_hash(&nd->last, nd->path.dentry, nd->flags);
 }
 
 /**
@@ -1913,7 +1975,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
        if (err)
                return ERR_PTR(err);
 
-       return __lookup_hash(&this, base, NULL);
+       return __lookup_hash(&this, base, 0);
 }
 
 int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
@@ -2086,10 +2148,9 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
 }
 
 int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool want_excl)
 {
        int error = may_create(dir, dentry);
-
        if (error)
                return error;
 
@@ -2100,7 +2161,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        error = security_inode_create(dir, dentry, mode);
        if (error)
                return error;
-       error = dir->i_op->create(dir, dentry, mode, nd);
+       error = dir->i_op->create(dir, dentry, mode, want_excl);
        if (!error)
                fsnotify_create(dir, dentry);
        return error;
@@ -2187,21 +2248,275 @@ static inline int open_to_namei_flags(int flag)
        return flag;
 }
 
+static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
+{
+       int error = security_path_mknod(dir, dentry, mode, 0);
+       if (error)
+               return error;
+
+       error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
+       if (error)
+               return error;
+
+       return security_inode_create(dir->dentry->d_inode, dentry, mode);
+}
+
 /*
- * Handle the last step of open()
+ * Attempt to atomically look up, create and open a file from a negative
+ * dentry.
+ *
+ * Returns 0 if successful.  The file will have been created and attached to
+ * @file by the filesystem calling finish_open().
+ *
+ * Returns 1 if the file was looked up only or didn't need creating.  The
+ * caller will need to perform the open themselves.  @path will have been
+ * updated to point to the new dentry.  This may be negative.
+ *
+ * Returns an error code otherwise.
+ */
+static int atomic_open(struct nameidata *nd, struct dentry *dentry,
+                       struct path *path, struct file *file,
+                       const struct open_flags *op,
+                       bool *want_write, bool need_lookup,
+                       int *opened)
+{
+       struct inode *dir =  nd->path.dentry->d_inode;
+       unsigned open_flag = open_to_namei_flags(op->open_flag);
+       umode_t mode;
+       int error;
+       int acc_mode;
+       int create_error = 0;
+       struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
+
+       BUG_ON(dentry->d_inode);
+
+       /* Don't create child dentry for a dead directory. */
+       if (unlikely(IS_DEADDIR(dir))) {
+               error = -ENOENT;
+               goto out;
+       }
+
+       mode = op->mode & S_IALLUGO;
+       if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
+               mode &= ~current_umask();
+
+       if (open_flag & O_EXCL) {
+               open_flag &= ~O_TRUNC;
+               *opened |= FILE_CREATED;
+       }
+
+       /*
+        * Checking write permission is tricky, bacuse we don't know if we are
+        * going to actually need it: O_CREAT opens should work as long as the
+        * file exists.  But checking existence breaks atomicity.  The trick is
+        * to check access and if not granted clear O_CREAT from the flags.
+        *
+        * Another problem is returing the "right" error value (e.g. for an
+        * O_EXCL open we want to return EEXIST not EROFS).
+        */
+       if ((open_flag & (O_CREAT | O_TRUNC)) ||
+           (open_flag & O_ACCMODE) != O_RDONLY) {
+               error = mnt_want_write(nd->path.mnt);
+               if (!error) {
+                       *want_write = true;
+               } else if (!(open_flag & O_CREAT)) {
+                       /*
+                        * No O_CREATE -> atomicity not a requirement -> fall
+                        * back to lookup + open
+                        */
+                       goto no_open;
+               } else if (open_flag & (O_EXCL | O_TRUNC)) {
+                       /* Fall back and fail with the right error */
+                       create_error = error;
+                       goto no_open;
+               } else {
+                       /* No side effects, safe to clear O_CREAT */
+                       create_error = error;
+                       open_flag &= ~O_CREAT;
+               }
+       }
+
+       if (open_flag & O_CREAT) {
+               error = may_o_create(&nd->path, dentry, op->mode);
+               if (error) {
+                       create_error = error;
+                       if (open_flag & O_EXCL)
+                               goto no_open;
+                       open_flag &= ~O_CREAT;
+               }
+       }
+
+       if (nd->flags & LOOKUP_DIRECTORY)
+               open_flag |= O_DIRECTORY;
+
+       file->f_path.dentry = DENTRY_NOT_SET;
+       file->f_path.mnt = nd->path.mnt;
+       error = dir->i_op->atomic_open(dir, dentry, file, open_flag, mode,
+                                     opened);
+       if (error < 0) {
+               if (create_error && error == -ENOENT)
+                       error = create_error;
+               goto out;
+       }
+
+       acc_mode = op->acc_mode;
+       if (*opened & FILE_CREATED) {
+               fsnotify_create(dir, dentry);
+               acc_mode = MAY_OPEN;
+       }
+
+       if (error) {    /* returned 1, that is */
+               if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
+                       error = -EIO;
+                       goto out;
+               }
+               if (file->f_path.dentry) {
+                       dput(dentry);
+                       dentry = file->f_path.dentry;
+               }
+               goto looked_up;
+       }
+
+       /*
+        * We didn't have the inode before the open, so check open permission
+        * here.
+        */
+       error = may_open(&file->f_path, acc_mode, open_flag);
+       if (error)
+               fput(file);
+
+out:
+       dput(dentry);
+       return error;
+
+no_open:
+       if (need_lookup) {
+               dentry = lookup_real(dir, dentry, nd->flags);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+
+               if (create_error) {
+                       int open_flag = op->open_flag;
+
+                       error = create_error;
+                       if ((open_flag & O_EXCL)) {
+                               if (!dentry->d_inode)
+                                       goto out;
+                       } else if (!dentry->d_inode) {
+                               goto out;
+                       } else if ((open_flag & O_TRUNC) &&
+                                  S_ISREG(dentry->d_inode->i_mode)) {
+                               goto out;
+                       }
+                       /* will fail later, go on to get the right error */
+               }
+       }
+looked_up:
+       path->dentry = dentry;
+       path->mnt = nd->path.mnt;
+       return 1;
+}
+
+/*
+ * Look up and maybe create and open the last component.
+ *
+ * Must be called with i_mutex held on parent.
+ *
+ * Returns 0 if the file was successfully atomically created (if necessary) and
+ * opened.  In this case the file will be returned attached to @file.
+ *
+ * Returns 1 if the file was not completely opened at this time, though lookups
+ * and creations will have been performed and the dentry returned in @path will
+ * be positive upon return if O_CREAT was specified.  If O_CREAT wasn't
+ * specified then a negative dentry may be returned.
+ *
+ * An error code is returned otherwise.
+ *
+ * FILE_CREATE will be set in @*opened if the dentry was created and will be
+ * cleared otherwise prior to returning.
  */
-static struct file *do_last(struct nameidata *nd, struct path *path,
-                           const struct open_flags *op, const char *pathname)
+static int lookup_open(struct nameidata *nd, struct path *path,
+                       struct file *file,
+                       const struct open_flags *op,
+                       bool *want_write, int *opened)
 {
        struct dentry *dir = nd->path.dentry;
+       struct inode *dir_inode = dir->d_inode;
        struct dentry *dentry;
+       int error;
+       bool need_lookup;
+
+       *opened &= ~FILE_CREATED;
+       dentry = lookup_dcache(&nd->last, dir, nd->flags, &need_lookup);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+
+       /* Cached positive dentry: will open in f_op->open */
+       if (!need_lookup && dentry->d_inode)
+               goto out_no_open;
+
+       if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
+               return atomic_open(nd, dentry, path, file, op, want_write,
+                                  need_lookup, opened);
+       }
+
+       if (need_lookup) {
+               BUG_ON(dentry->d_inode);
+
+               dentry = lookup_real(dir_inode, dentry, nd->flags);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+       }
+
+       /* Negative dentry, just create the file */
+       if (!dentry->d_inode && (op->open_flag & O_CREAT)) {
+               umode_t mode = op->mode;
+               if (!IS_POSIXACL(dir->d_inode))
+                       mode &= ~current_umask();
+               /*
+                * This write is needed to ensure that a
+                * rw->ro transition does not occur between
+                * the time when the file is created and when
+                * a permanent write count is taken through
+                * the 'struct file' in finish_open().
+                */
+               error = mnt_want_write(nd->path.mnt);
+               if (error)
+                       goto out_dput;
+               *want_write = true;
+               *opened |= FILE_CREATED;
+               error = security_path_mknod(&nd->path, dentry, mode, 0);
+               if (error)
+                       goto out_dput;
+               error = vfs_create(dir->d_inode, dentry, mode,
+                                  nd->flags & LOOKUP_EXCL);
+               if (error)
+                       goto out_dput;
+       }
+out_no_open:
+       path->dentry = dentry;
+       path->mnt = nd->path.mnt;
+       return 1;
+
+out_dput:
+       dput(dentry);
+       return error;
+}
+
+/*
+ * Handle the last step of open()
+ */
+static int do_last(struct nameidata *nd, struct path *path,
+                  struct file *file, const struct open_flags *op,
+                  int *opened, const char *pathname)
+{
+       struct dentry *dir = nd->path.dentry;
        int open_flag = op->open_flag;
-       int will_truncate = open_flag & O_TRUNC;
-       int want_write = 0;
+       bool will_truncate = (open_flag & O_TRUNC) != 0;
+       bool want_write = false;
        int acc_mode = op->acc_mode;
-       struct file *filp;
        struct inode *inode;
-       int symlink_ok = 0;
+       bool symlink_ok = false;
        struct path save_parent = { .dentry = NULL, .mnt = NULL };
        bool retried = false;
        int error;
@@ -2214,112 +2529,99 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        case LAST_DOT:
                error = handle_dots(nd, nd->last_type);
                if (error)
-                       return ERR_PTR(error);
+                       return error;
                /* fallthrough */
        case LAST_ROOT:
                error = complete_walk(nd);
                if (error)
-                       return ERR_PTR(error);
+                       return error;
                audit_inode(pathname, nd->path.dentry);
                if (open_flag & O_CREAT) {
                        error = -EISDIR;
-                       goto exit;
+                       goto out;
                }
-               goto ok;
+               goto finish_open;
        case LAST_BIND:
                error = complete_walk(nd);
                if (error)
-                       return ERR_PTR(error);
+                       return error;
                audit_inode(pathname, dir);
-               goto ok;
+               goto finish_open;
        }
 
        if (!(open_flag & O_CREAT)) {
                if (nd->last.name[nd->last.len])
                        nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
                if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
-                       symlink_ok = 1;
+                       symlink_ok = true;
                /* we _can_ be in RCU mode here */
                error = lookup_fast(nd, &nd->last, path, &inode);
-               if (unlikely(error)) {
-                       if (error < 0)
-                               goto exit;
+               if (likely(!error))
+                       goto finish_lookup;
 
-                       error = lookup_slow(nd, &nd->last, path);
-                       if (error < 0)
-                               goto exit;
+               if (error < 0)
+                       goto out;
 
-                       inode = path->dentry->d_inode;
-               }
-               goto finish_lookup;
-       }
-
-       /* create side of things */
-       /*
-        * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been
-        * cleared when we got to the last component we are about to look up
-        */
-       error = complete_walk(nd);
-       if (error)
-               return ERR_PTR(error);
+               BUG_ON(nd->inode != dir->d_inode);
+       } else {
+               /* create side of things */
+               /*
+                * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED
+                * has been cleared when we got to the last component we are
+                * about to look up
+                */
+               error = complete_walk(nd);
+               if (error)
+                       return error;
 
-       audit_inode(pathname, dir);
-       error = -EISDIR;
-       /* trailing slashes? */
-       if (nd->last.name[nd->last.len])
-               goto exit;
+               audit_inode(pathname, dir);
+               error = -EISDIR;
+               /* trailing slashes? */
+               if (nd->last.name[nd->last.len])
+                       goto out;
+       }
 
 retry_lookup:
        mutex_lock(&dir->d_inode->i_mutex);
+       error = lookup_open(nd, path, file, op, &want_write, opened);
+       mutex_unlock(&dir->d_inode->i_mutex);
 
-       dentry = lookup_hash(nd);
-       error = PTR_ERR(dentry);
-       if (IS_ERR(dentry)) {
-               mutex_unlock(&dir->d_inode->i_mutex);
-               goto exit;
-       }
+       if (error <= 0) {
+               if (error)
+                       goto out;
 
-       path->dentry = dentry;
-       path->mnt = nd->path.mnt;
+               if ((*opened & FILE_CREATED) ||
+                   !S_ISREG(file->f_path.dentry->d_inode->i_mode))
+                       will_truncate = false;
 
-       /* Negative dentry, just create the file */
-       if (!dentry->d_inode) {
-               umode_t mode = op->mode;
-               if (!IS_POSIXACL(dir->d_inode))
-                       mode &= ~current_umask();
-               /*
-                * This write is needed to ensure that a
-                * rw->ro transition does not occur between
-                * the time when the file is created and when
-                * a permanent write count is taken through
-                * the 'struct file' in nameidata_to_filp().
-                */
-               error = mnt_want_write(nd->path.mnt);
-               if (error)
-                       goto exit_mutex_unlock;
-               want_write = 1;
+               audit_inode(pathname, file->f_path.dentry);
+               goto opened;
+       }
+
+       if (*opened & FILE_CREATED) {
                /* Don't check for write permission, don't truncate */
                open_flag &= ~O_TRUNC;
-               will_truncate = 0;
+               will_truncate = false;
                acc_mode = MAY_OPEN;
-               error = security_path_mknod(&nd->path, dentry, mode, 0);
-               if (error)
-                       goto exit_mutex_unlock;
-               error = vfs_create(dir->d_inode, dentry, mode, nd);
-               if (error)
-                       goto exit_mutex_unlock;
-               mutex_unlock(&dir->d_inode->i_mutex);
-               dput(nd->path.dentry);
-               nd->path.dentry = dentry;
-               goto common;
+               path_to_nameidata(path, nd);
+               goto finish_open_created;
        }
 
        /*
         * It already exists.
         */
-       mutex_unlock(&dir->d_inode->i_mutex);
        audit_inode(pathname, path->dentry);
 
+       /*
+        * If atomic_open() acquired write access it is dropped now due to
+        * possible mount and symlink following (this might be optimized away if
+        * necessary...)
+        */
+       if (want_write) {
+               mnt_drop_write(nd->path.mnt);
+               want_write = false;
+       }
+
        error = -EEXIST;
        if (open_flag & O_EXCL)
                goto exit_dput;
@@ -2338,18 +2640,18 @@ finish_lookup:
        error = -ENOENT;
        if (!inode) {
                path_to_nameidata(path, nd);
-               goto exit;
+               goto out;
        }
 
        if (should_follow_link(inode, !symlink_ok)) {
                if (nd->flags & LOOKUP_RCU) {
                        if (unlikely(unlazy_walk(nd, path->dentry))) {
                                error = -ECHILD;
-                               goto exit;
+                               goto out;
                        }
                }
                BUG_ON(inode != path->dentry->d_inode);
-               return NULL;
+               return 1;
        }
 
        if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) {
@@ -2365,119 +2667,122 @@ finish_lookup:
        error = complete_walk(nd);
        if (error) {
                path_put(&save_parent);
-               return ERR_PTR(error);
+               return error;
        }
        error = -EISDIR;
        if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
-               goto exit;
+               goto out;
        error = -ENOTDIR;
        if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
-               goto exit;
+               goto out;
        audit_inode(pathname, nd->path.dentry);
-ok:
+finish_open:
        if (!S_ISREG(nd->inode->i_mode))
-               will_truncate = 0;
+               will_truncate = false;
 
        if (will_truncate) {
                error = mnt_want_write(nd->path.mnt);
                if (error)
-                       goto exit;
-               want_write = 1;
+                       goto out;
+               want_write = true;
        }
-common:
+finish_open_created:
        error = may_open(&nd->path, acc_mode, open_flag);
        if (error)
-               goto exit;
-       filp = nameidata_to_filp(nd);
-       if (filp == ERR_PTR(-EOPENSTALE) && save_parent.dentry && !retried) {
-               BUG_ON(save_parent.dentry != dir);
-               path_put(&nd->path);
-               nd->path = save_parent;
-               nd->inode = dir->d_inode;
-               save_parent.mnt = NULL;
-               save_parent.dentry = NULL;
-               if (want_write) {
-                       mnt_drop_write(nd->path.mnt);
-                       want_write = 0;
-               }
-               retried = true;
-               goto retry_lookup;
-       }
-       if (!IS_ERR(filp)) {
-               error = ima_file_check(filp, op->acc_mode);
-               if (error) {
-                       fput(filp);
-                       filp = ERR_PTR(error);
-               }
+               goto out;
+       file->f_path.mnt = nd->path.mnt;
+       error = finish_open(file, nd->path.dentry, NULL, opened);
+       if (error) {
+               if (error == -EOPENSTALE)
+                       goto stale_open;
+               goto out;
        }
-       if (!IS_ERR(filp)) {
-               if (will_truncate) {
-                       error = handle_truncate(filp);
-                       if (error) {
-                               fput(filp);
-                               filp = ERR_PTR(error);
-                       }
-               }
+opened:
+       error = open_check_o_direct(file);
+       if (error)
+               goto exit_fput;
+       error = ima_file_check(file, op->acc_mode);
+       if (error)
+               goto exit_fput;
+
+       if (will_truncate) {
+               error = handle_truncate(file);
+               if (error)
+                       goto exit_fput;
        }
 out:
        if (want_write)
                mnt_drop_write(nd->path.mnt);
        path_put(&save_parent);
        terminate_walk(nd);
-       return filp;
+       return error;
 
-exit_mutex_unlock:
-       mutex_unlock(&dir->d_inode->i_mutex);
 exit_dput:
        path_put_conditional(path, nd);
-exit:
-       filp = ERR_PTR(error);
        goto out;
+exit_fput:
+       fput(file);
+       goto out;
+
+stale_open:
+       /* If no saved parent or already retried then can't retry */
+       if (!save_parent.dentry || retried)
+               goto out;
+
+       BUG_ON(save_parent.dentry != dir);
+       path_put(&nd->path);
+       nd->path = save_parent;
+       nd->inode = dir->d_inode;
+       save_parent.mnt = NULL;
+       save_parent.dentry = NULL;
+       if (want_write) {
+               mnt_drop_write(nd->path.mnt);
+               want_write = false;
+       }
+       retried = true;
+       goto retry_lookup;
 }
 
 static struct file *path_openat(int dfd, const char *pathname,
                struct nameidata *nd, const struct open_flags *op, int flags)
 {
        struct file *base = NULL;
-       struct file *filp;
+       struct file *file;
        struct path path;
+       int opened = 0;
        int error;
 
-       filp = get_empty_filp();
-       if (!filp)
+       file = get_empty_filp();
+       if (!file)
                return ERR_PTR(-ENFILE);
 
-       filp->f_flags = op->open_flag;
-       nd->intent.open.file = filp;
-       nd->intent.open.flags = open_to_namei_flags(op->open_flag);
-       nd->intent.open.create_mode = op->mode;
+       file->f_flags = op->open_flag;
 
        error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
        if (unlikely(error))
-               goto out_filp;
+               goto out;
 
        current->total_link_count = 0;
        error = link_path_walk(pathname, nd);
        if (unlikely(error))
-               goto out_filp;
+               goto out;
 
-       filp = do_last(nd, &path, op, pathname);
-       while (unlikely(!filp)) { /* trailing symlink */
+       error = do_last(nd, &path, file, op, &opened, pathname);
+       while (unlikely(error > 0)) { /* trailing symlink */
                struct path link = path;
                void *cookie;
                if (!(nd->flags & LOOKUP_FOLLOW)) {
                        path_put_conditional(&path, nd);
                        path_put(&nd->path);
-                       filp = ERR_PTR(-ELOOP);
+                       error = -ELOOP;
                        break;
                }
                nd->flags |= LOOKUP_PARENT;
                nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
                error = follow_link(&link, nd, &cookie);
                if (unlikely(error))
-                       filp = ERR_PTR(error);
-               else
-                       filp = do_last(nd, &path, op, pathname);
+                       break;
+               error = do_last(nd, &path, file, op, &opened, pathname);
                put_link(nd, &link, cookie);
        }
 out:
@@ -2485,18 +2790,20 @@ out:
                path_put(&nd->root);
        if (base)
                fput(base);
-       release_open_intent(nd);
-       if (filp == ERR_PTR(-EOPENSTALE)) {
-               if (flags & LOOKUP_RCU)
-                       filp = ERR_PTR(-ECHILD);
-               else
-                       filp = ERR_PTR(-ESTALE);
+       if (!(opened & FILE_OPENED)) {
+               BUG_ON(!error);
+               put_filp(file);
        }
-       return filp;
-
-out_filp:
-       filp = ERR_PTR(error);
-       goto out;
+       if (unlikely(error)) {
+               if (error == -EOPENSTALE) {
+                       if (flags & LOOKUP_RCU)
+                               error = -ECHILD;
+                       else
+                               error = -ESTALE;
+               }
+               file = ERR_PTR(error);
+       }
+       return file;
 }
 
 struct file *do_filp_open(int dfd, const char *pathname,
@@ -2551,7 +2858,6 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
                goto out;
        nd.flags &= ~LOOKUP_PARENT;
        nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL;
-       nd.intent.open.flags = O_EXCL;
 
        /*
         * Do the final lookup.
@@ -2670,7 +2976,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
                goto out_drop_write;
        switch (mode & S_IFMT) {
                case 0: case S_IFREG:
-                       error = vfs_create(path.dentry->d_inode,dentry,mode,NULL);
+                       error = vfs_create(path.dentry->d_inode,dentry,mode,true);
                        break;
                case S_IFCHR: case S_IFBLK:
                        error = vfs_mknod(path.dentry->d_inode,dentry,mode,
index 1e4a5fe3d7b7f789d66839f37b1f917c1fa3e2ba..c53d3381b0d0043d91e2f7c47e4cafbdaaaf13d6 100644 (file)
@@ -515,8 +515,20 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,
 }
 
 /*
- * lookup_mnt increments the ref count before returning
- * the vfsmount struct.
+ * lookup_mnt - Return the first child mount mounted at path
+ *
+ * "First" means first mounted chronologically.  If you create the
+ * following mounts:
+ *
+ * mount /dev/sda1 /mnt
+ * mount /dev/sda2 /mnt
+ * mount /dev/sda3 /mnt
+ *
+ * Then lookup_mnt() on the base /mnt dentry in the root mount will
+ * return successively the root dentry and vfsmount of /dev/sda1, then
+ * /dev/sda2, then /dev/sda3, then NULL.
+ *
+ * lookup_mnt takes a reference to the found vfsmount.
  */
 struct vfsmount *lookup_mnt(struct path *path)
 {
@@ -621,21 +633,6 @@ static void attach_mnt(struct mount *mnt, struct path *path)
        list_add_tail(&mnt->mnt_child, &real_mount(path->mnt)->mnt_mounts);
 }
 
-static inline void __mnt_make_longterm(struct mount *mnt)
-{
-#ifdef CONFIG_SMP
-       atomic_inc(&mnt->mnt_longterm);
-#endif
-}
-
-/* needs vfsmount lock for write */
-static inline void __mnt_make_shortterm(struct mount *mnt)
-{
-#ifdef CONFIG_SMP
-       atomic_dec(&mnt->mnt_longterm);
-#endif
-}
-
 /*
  * vfsmount lock must be held for write
  */
@@ -649,10 +646,8 @@ static void commit_tree(struct mount *mnt)
        BUG_ON(parent == mnt);
 
        list_add_tail(&head, &mnt->mnt_list);
-       list_for_each_entry(m, &head, mnt_list) {
+       list_for_each_entry(m, &head, mnt_list)
                m->mnt_ns = n;
-               __mnt_make_longterm(m);
-       }
 
        list_splice(&head, n->list.prev);
 
@@ -725,56 +720,60 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
                                        int flag)
 {
        struct super_block *sb = old->mnt.mnt_sb;
-       struct mount *mnt = alloc_vfsmnt(old->mnt_devname);
+       struct mount *mnt;
+       int err;
 
-       if (mnt) {
-               if (flag & (CL_SLAVE | CL_PRIVATE))
-                       mnt->mnt_group_id = 0; /* not a peer of original */
-               else
-                       mnt->mnt_group_id = old->mnt_group_id;
-
-               if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
-                       int err = mnt_alloc_group_id(mnt);
-                       if (err)
-                               goto out_free;
-               }
+       mnt = alloc_vfsmnt(old->mnt_devname);
+       if (!mnt)
+               return ERR_PTR(-ENOMEM);
 
-               mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD;
-               atomic_inc(&sb->s_active);
-               mnt->mnt.mnt_sb = sb;
-               mnt->mnt.mnt_root = dget(root);
-               mnt->mnt_mountpoint = mnt->mnt.mnt_root;
-               mnt->mnt_parent = mnt;
-               br_write_lock(&vfsmount_lock);
-               list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
-               br_write_unlock(&vfsmount_lock);
+       if (flag & (CL_SLAVE | CL_PRIVATE))
+               mnt->mnt_group_id = 0; /* not a peer of original */
+       else
+               mnt->mnt_group_id = old->mnt_group_id;
 
-               if (flag & CL_SLAVE) {
-                       list_add(&mnt->mnt_slave, &old->mnt_slave_list);
-                       mnt->mnt_master = old;
-                       CLEAR_MNT_SHARED(mnt);
-               } else if (!(flag & CL_PRIVATE)) {
-                       if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old))
-                               list_add(&mnt->mnt_share, &old->mnt_share);
-                       if (IS_MNT_SLAVE(old))
-                               list_add(&mnt->mnt_slave, &old->mnt_slave);
-                       mnt->mnt_master = old->mnt_master;
-               }
-               if (flag & CL_MAKE_SHARED)
-                       set_mnt_shared(mnt);
-
-               /* stick the duplicate mount on the same expiry list
-                * as the original if that was on one */
-               if (flag & CL_EXPIRE) {
-                       if (!list_empty(&old->mnt_expire))
-                               list_add(&mnt->mnt_expire, &old->mnt_expire);
-               }
+       if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
+               err = mnt_alloc_group_id(mnt);
+               if (err)
+                       goto out_free;
        }
+
+       mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD;
+       atomic_inc(&sb->s_active);
+       mnt->mnt.mnt_sb = sb;
+       mnt->mnt.mnt_root = dget(root);
+       mnt->mnt_mountpoint = mnt->mnt.mnt_root;
+       mnt->mnt_parent = mnt;
+       br_write_lock(&vfsmount_lock);
+       list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
+       br_write_unlock(&vfsmount_lock);
+
+       if (flag & CL_SLAVE) {
+               list_add(&mnt->mnt_slave, &old->mnt_slave_list);
+               mnt->mnt_master = old;
+               CLEAR_MNT_SHARED(mnt);
+       } else if (!(flag & CL_PRIVATE)) {
+               if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old))
+                       list_add(&mnt->mnt_share, &old->mnt_share);
+               if (IS_MNT_SLAVE(old))
+                       list_add(&mnt->mnt_slave, &old->mnt_slave);
+               mnt->mnt_master = old->mnt_master;
+       }
+       if (flag & CL_MAKE_SHARED)
+               set_mnt_shared(mnt);
+
+       /* stick the duplicate mount on the same expiry list
+        * as the original if that was on one */
+       if (flag & CL_EXPIRE) {
+               if (!list_empty(&old->mnt_expire))
+                       list_add(&mnt->mnt_expire, &old->mnt_expire);
+       }
+
        return mnt;
 
  out_free:
        free_vfsmnt(mnt);
-       return NULL;
+       return ERR_PTR(err);
 }
 
 static inline void mntfree(struct mount *mnt)
@@ -804,7 +803,8 @@ static void mntput_no_expire(struct mount *mnt)
 put_again:
 #ifdef CONFIG_SMP
        br_read_lock(&vfsmount_lock);
-       if (likely(atomic_read(&mnt->mnt_longterm))) {
+       if (likely(mnt->mnt_ns)) {
+               /* shouldn't be the last one */
                mnt_add_count(mnt, -1);
                br_read_unlock(&vfsmount_lock);
                return;
@@ -939,7 +939,7 @@ EXPORT_SYMBOL(replace_mount_options);
 /* iterator; we want it to have access to namespace_sem, thus here... */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
-       struct proc_mounts *p = container_of(m, struct proc_mounts, m);
+       struct proc_mounts *p = proc_mounts(m);
 
        down_read(&namespace_sem);
        return seq_list_start(&p->ns->list, *pos);
@@ -947,7 +947,7 @@ static void *m_start(struct seq_file *m, loff_t *pos)
 
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct proc_mounts *p = container_of(m, struct proc_mounts, m);
+       struct proc_mounts *p = proc_mounts(m);
 
        return seq_list_next(v, &p->ns->list, pos);
 }
@@ -959,7 +959,7 @@ static void m_stop(struct seq_file *m, void *v)
 
 static int m_show(struct seq_file *m, void *v)
 {
-       struct proc_mounts *p = container_of(m, struct proc_mounts, m);
+       struct proc_mounts *p = proc_mounts(m);
        struct mount *r = list_entry(v, struct mount, mnt_list);
        return p->show(m, &r->mnt);
 }
@@ -1074,8 +1074,6 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill)
                list_del_init(&p->mnt_expire);
                list_del_init(&p->mnt_list);
                __touch_mnt_namespace(p->mnt_ns);
-               if (p->mnt_ns)
-                       __mnt_make_shortterm(p);
                p->mnt_ns = NULL;
                list_del_init(&p->mnt_child);
                if (mnt_has_parent(p)) {
@@ -1260,11 +1258,12 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
        struct path path;
 
        if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt))
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        res = q = clone_mnt(mnt, dentry, flag);
-       if (!q)
-               goto Enomem;
+       if (IS_ERR(q))
+               return q;
+
        q->mnt_mountpoint = mnt->mnt_mountpoint;
 
        p = mnt;
@@ -1286,8 +1285,8 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
                        path.mnt = &q->mnt;
                        path.dentry = p->mnt_mountpoint;
                        q = clone_mnt(p, p->mnt.mnt_root, flag);
-                       if (!q)
-                               goto Enomem;
+                       if (IS_ERR(q))
+                               goto out;
                        br_write_lock(&vfsmount_lock);
                        list_add_tail(&q->mnt_list, &res->mnt_list);
                        attach_mnt(q, &path);
@@ -1295,7 +1294,7 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
                }
        }
        return res;
-Enomem:
+out:
        if (res) {
                LIST_HEAD(umount_list);
                br_write_lock(&vfsmount_lock);
@@ -1303,9 +1302,11 @@ Enomem:
                br_write_unlock(&vfsmount_lock);
                release_mounts(&umount_list);
        }
-       return NULL;
+       return q;
 }
 
+/* Caller should check returned pointer for errors */
+
 struct vfsmount *collect_mounts(struct path *path)
 {
        struct mount *tree;
@@ -1313,7 +1314,9 @@ struct vfsmount *collect_mounts(struct path *path)
        tree = copy_tree(real_mount(path->mnt), path->dentry,
                         CL_COPY_ALL | CL_PRIVATE);
        up_write(&namespace_sem);
-       return tree ? &tree->mnt : NULL;
+       if (IS_ERR(tree))
+               return NULL;
+       return &tree->mnt;
 }
 
 void drop_collected_mounts(struct vfsmount *mnt)
@@ -1608,14 +1611,15 @@ static int do_loopback(struct path *path, char *old_name,
        if (!check_mnt(real_mount(path->mnt)) || !check_mnt(old))
                goto out2;
 
-       err = -ENOMEM;
        if (recurse)
                mnt = copy_tree(old, old_path.dentry, 0);
        else
                mnt = clone_mnt(old, old_path.dentry, 0);
 
-       if (!mnt)
-               goto out2;
+       if (IS_ERR(mnt)) {
+               err = PTR_ERR(mnt);
+               goto out;
+       }
 
        err = graft_tree(mnt, path);
        if (err) {
@@ -2209,23 +2213,6 @@ static struct mnt_namespace *alloc_mnt_ns(void)
        return new_ns;
 }
 
-void mnt_make_longterm(struct vfsmount *mnt)
-{
-       __mnt_make_longterm(real_mount(mnt));
-}
-
-void mnt_make_shortterm(struct vfsmount *m)
-{
-#ifdef CONFIG_SMP
-       struct mount *mnt = real_mount(m);
-       if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
-               return;
-       br_write_lock(&vfsmount_lock);
-       atomic_dec(&mnt->mnt_longterm);
-       br_write_unlock(&vfsmount_lock);
-#endif
-}
-
 /*
  * Allocate a new namespace structure and populate it with contents
  * copied from the namespace of the passed in task structure.
@@ -2246,10 +2233,10 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        down_write(&namespace_sem);
        /* First pass: copy the tree topology */
        new = copy_tree(old, old->mnt.mnt_root, CL_COPY_ALL | CL_EXPIRE);
-       if (!new) {
+       if (IS_ERR(new)) {
                up_write(&namespace_sem);
                kfree(new_ns);
-               return ERR_PTR(-ENOMEM);
+               return ERR_CAST(new);
        }
        new_ns->root = new;
        br_write_lock(&vfsmount_lock);
@@ -2265,18 +2252,13 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        q = new;
        while (p) {
                q->mnt_ns = new_ns;
-               __mnt_make_longterm(q);
                if (fs) {
                        if (&p->mnt == fs->root.mnt) {
                                fs->root.mnt = mntget(&q->mnt);
-                               __mnt_make_longterm(q);
-                               mnt_make_shortterm(&p->mnt);
                                rootmnt = &p->mnt;
                        }
                        if (&p->mnt == fs->pwd.mnt) {
                                fs->pwd.mnt = mntget(&q->mnt);
-                               __mnt_make_longterm(q);
-                               mnt_make_shortterm(&p->mnt);
                                pwdmnt = &p->mnt;
                        }
                }
@@ -2320,7 +2302,6 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m)
        if (!IS_ERR(new_ns)) {
                struct mount *mnt = real_mount(m);
                mnt->mnt_ns = new_ns;
-               __mnt_make_longterm(mnt);
                new_ns->root = mnt;
                list_add(&new_ns->list, &mnt->mnt_list);
        } else {
@@ -2615,7 +2596,7 @@ struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
                 * it is a longterm mount, don't release mnt until
                 * we unmount before file sys is unregistered
                */
-               mnt_make_longterm(mnt);
+               real_mount(mnt)->mnt_ns = MNT_NS_INTERNAL;
        }
        return mnt;
 }
@@ -2625,7 +2606,9 @@ void kern_unmount(struct vfsmount *mnt)
 {
        /* release long term mount so mount point can be released */
        if (!IS_ERR_OR_NULL(mnt)) {
-               mnt_make_shortterm(mnt);
+               br_write_lock(&vfsmount_lock);
+               real_mount(mnt)->mnt_ns = NULL;
+               br_write_unlock(&vfsmount_lock);
                mntput(mnt);
        }
 }
index aeed93a6bde0c972796b92972ec5cea58126dc75..4117e7b377bbf731a5345ef8b640ad5aa6607837 100644 (file)
@@ -30,8 +30,8 @@ static void ncp_do_readdir(struct file *, void *, filldir_t,
 
 static int ncp_readdir(struct file *, void *, filldir_t);
 
-static int ncp_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
-static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *);
+static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
+static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
 static int ncp_unlink(struct inode *, struct dentry *);
 static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
 static int ncp_rmdir(struct inode *, struct dentry *);
@@ -72,7 +72,7 @@ const struct inode_operations ncp_dir_inode_operations =
 /*
  * Dentry operations routines
  */
-static int ncp_lookup_validate(struct dentry *, struct nameidata *);
+static int ncp_lookup_validate(struct dentry *, unsigned int);
 static int ncp_hash_dentry(const struct dentry *, const struct inode *,
                struct qstr *);
 static int ncp_compare_dentry(const struct dentry *, const struct inode *,
@@ -290,7 +290,7 @@ leave_me:;
 
 
 static int
-ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
+ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
 {
        struct ncp_server *server;
        struct dentry *parent;
@@ -302,7 +302,7 @@ ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
        if (dentry == dentry->d_sb->s_root)
                return 1;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        parent = dget_parent(dentry);
@@ -836,7 +836,7 @@ out:
        return result;
 }
 
-static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct ncp_server *server = NCP_SERVER(dir);
        struct inode *inode = NULL;
@@ -980,7 +980,7 @@ out:
 }
 
 static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        return ncp_create_new(dir, dentry, mode, 0, 0);
 }
index f430057ff3b397c2fe1f523bf5fcea4135276f8c..a6b1c7fb8232c0a3152f79175e2047421c896859 100644 (file)
@@ -46,8 +46,8 @@
 static int nfs_opendir(struct inode *, struct file *);
 static int nfs_closedir(struct inode *, struct file *);
 static int nfs_readdir(struct file *, void *, filldir_t);
-static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int nfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
+static struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
+static int nfs_create(struct inode *, struct dentry *, umode_t, bool);
 static int nfs_mkdir(struct inode *, struct dentry *, umode_t);
 static int nfs_rmdir(struct inode *, struct dentry *);
 static int nfs_unlink(struct inode *, struct dentry *);
@@ -111,11 +111,13 @@ const struct inode_operations nfs3_dir_inode_operations = {
 
 #ifdef CONFIG_NFS_V4
 
-static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
-static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd);
+static int nfs_atomic_open(struct inode *, struct dentry *,
+                          struct file *, unsigned, umode_t,
+                          int *);
 const struct inode_operations nfs4_dir_inode_operations = {
-       .create         = nfs_open_create,
-       .lookup         = nfs_atomic_lookup,
+       .create         = nfs_create,
+       .lookup         = nfs_lookup,
+       .atomic_open    = nfs_atomic_open,
        .link           = nfs_link,
        .unlink         = nfs_unlink,
        .symlink        = nfs_symlink,
@@ -1028,28 +1030,15 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
        return 1;
 }
 
-/*
- * Return the intent data that applies to this particular path component
- *
- * Note that the current set of intents only apply to the very last
- * component of the path and none of them is set before that last
- * component.
- */
-static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd,
-                                               unsigned int mask)
-{
-       return nd->flags & mask;
-}
-
 /*
  * Use intent information to check whether or not we're going to do
  * an O_EXCL create using this path component.
  */
-static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
+static int nfs_is_exclusive_create(struct inode *dir, unsigned int flags)
 {
        if (NFS_PROTO(dir)->version == 2)
                return 0;
-       return nd && nfs_lookup_check_intent(nd, LOOKUP_EXCL);
+       return flags & LOOKUP_EXCL;
 }
 
 /*
@@ -1061,25 +1050,20 @@ static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
  *
  */
 static inline
-int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
+int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
 {
        struct nfs_server *server = NFS_SERVER(inode);
 
        if (IS_AUTOMOUNT(inode))
                return 0;
-       if (nd != NULL) {
-               /* VFS wants an on-the-wire revalidation */
-               if (nd->flags & LOOKUP_REVAL)
-                       goto out_force;
-               /* This is an open(2) */
-               if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
-                               !(server->flags & NFS_MOUNT_NOCTO) &&
-                               (S_ISREG(inode->i_mode) ||
-                                S_ISDIR(inode->i_mode)))
-                       goto out_force;
-               return 0;
-       }
-       return nfs_revalidate_inode(server, inode);
+       /* VFS wants an on-the-wire revalidation */
+       if (flags & LOOKUP_REVAL)
+               goto out_force;
+       /* This is an open(2) */
+       if ((flags & LOOKUP_OPEN) && !(server->flags & NFS_MOUNT_NOCTO) &&
+           (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
+               goto out_force;
+       return 0;
 out_force:
        return __nfs_revalidate_inode(server, inode);
 }
@@ -1093,10 +1077,10 @@ out_force:
  */
 static inline
 int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
-                      struct nameidata *nd)
+                      unsigned int flags)
 {
        /* Don't revalidate a negative dentry if we're creating a new file */
-       if (nd != NULL && nfs_lookup_check_intent(nd, LOOKUP_CREATE) != 0)
+       if (flags & LOOKUP_CREATE)
                return 0;
        if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG)
                return 1;
@@ -1114,7 +1098,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
  * If the parent directory is seen to have changed, we throw out the
  * cached dentry and do a new lookup.
  */
-static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct inode *dir;
        struct inode *inode;
@@ -1123,7 +1107,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct nfs_fattr *fattr = NULL;
        int error;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        parent = dget_parent(dentry);
@@ -1132,7 +1116,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        inode = dentry->d_inode;
 
        if (!inode) {
-               if (nfs_neg_need_reval(dir, dentry, nd))
+               if (nfs_neg_need_reval(dir, dentry, flags))
                        goto out_bad;
                goto out_valid_noent;
        }
@@ -1148,8 +1132,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
                goto out_set_verifier;
 
        /* Force a full look up iff the parent directory has changed */
-       if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
-               if (nfs_lookup_verify_inode(inode, nd))
+       if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) {
+               if (nfs_lookup_verify_inode(inode, flags))
                        goto out_zap_parent;
                goto out_valid;
        }
@@ -1286,7 +1270,7 @@ const struct dentry_operations nfs_dentry_operations = {
        .d_release      = nfs_d_release,
 };
 
-static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
        struct dentry *res;
        struct dentry *parent;
@@ -1307,7 +1291,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
         * If we're doing an exclusive create, optimize away the lookup
         * but don't hash the dentry.
         */
-       if (nfs_is_exclusive_create(dir, nd)) {
+       if (nfs_is_exclusive_create(dir, flags)) {
                d_instantiate(dentry, NULL);
                res = NULL;
                goto out;
@@ -1354,7 +1338,7 @@ out:
 }
 
 #ifdef CONFIG_NFS_V4
-static int nfs4_lookup_revalidate(struct dentry *, struct nameidata *);
+static int nfs4_lookup_revalidate(struct dentry *, unsigned int);
 
 const struct dentry_operations nfs4_dentry_operations = {
        .d_revalidate   = nfs4_lookup_revalidate,
@@ -1364,24 +1348,6 @@ const struct dentry_operations nfs4_dentry_operations = {
        .d_release      = nfs_d_release,
 };
 
-/*
- * Use intent information to determine whether we need to substitute
- * the NFSv4-style stateful OPEN for the LOOKUP call
- */
-static int is_atomic_open(struct nameidata *nd)
-{
-       if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_OPEN) == 0)
-               return 0;
-       /* NFS does not (yet) have a stateful open for directories */
-       if (nd->flags & LOOKUP_DIRECTORY)
-               return 0;
-       /* Are we trying to write to a read only partition? */
-       if (__mnt_is_readonly(nd->path.mnt) &&
-           (nd->intent.open.flags & (O_CREAT|O_TRUNC|O_ACCMODE)))
-               return 0;
-       return 1;
-}
-
 static fmode_t flags_to_mode(int flags)
 {
        fmode_t res = (__force fmode_t)flags & FMODE_EXEC;
@@ -1403,136 +1369,143 @@ static int do_open(struct inode *inode, struct file *filp)
        return 0;
 }
 
-static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx)
+static int nfs_finish_open(struct nfs_open_context *ctx,
+                          struct dentry *dentry,
+                          struct file *file, unsigned open_flags,
+                          int *opened)
 {
-       struct file *filp;
-       int ret = 0;
+       int err;
+
+       if (ctx->dentry != dentry) {
+               dput(ctx->dentry);
+               ctx->dentry = dget(dentry);
+       }
 
        /* If the open_intent is for execute, we have an extra check to make */
        if (ctx->mode & FMODE_EXEC) {
-               ret = nfs_may_open(ctx->dentry->d_inode,
-                               ctx->cred,
-                               nd->intent.open.flags);
-               if (ret < 0)
+               err = nfs_may_open(dentry->d_inode, ctx->cred, open_flags);
+               if (err < 0)
                        goto out;
        }
-       filp = lookup_instantiate_filp(nd, ctx->dentry, do_open);
-       if (IS_ERR(filp))
-               ret = PTR_ERR(filp);
-       else
-               nfs_file_set_open_context(filp, ctx);
+
+       err = finish_open(file, dentry, do_open, opened);
+       if (err)
+               goto out;
+       nfs_file_set_open_context(file, ctx);
+
 out:
        put_nfs_open_context(ctx);
-       return ret;
+       return err;
 }
 
-static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
+                           struct file *file, unsigned open_flags,
+                           umode_t mode, int *opened)
 {
        struct nfs_open_context *ctx;
-       struct iattr attr;
-       struct dentry *res = NULL;
+       struct dentry *res;
+       struct iattr attr = { .ia_valid = ATTR_OPEN };
        struct inode *inode;
-       int open_flags;
        int err;
 
-       dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n",
+       /* Expect a negative dentry */
+       BUG_ON(dentry->d_inode);
+
+       dfprintk(VFS, "NFS: atomic_open(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
-       /* Check that we are indeed trying to open this file */
-       if (!is_atomic_open(nd))
+       /* NFS only supports OPEN on regular files */
+       if ((open_flags & O_DIRECTORY)) {
+               if (!d_unhashed(dentry)) {
+                       /*
+                        * Hashed negative dentry with O_DIRECTORY: dentry was
+                        * revalidated and is fine, no need to perform lookup
+                        * again
+                        */
+                       return -ENOENT;
+               }
                goto no_open;
-
-       if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
-               res = ERR_PTR(-ENAMETOOLONG);
-               goto out;
-       }
-
-       /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
-        * the dentry. */
-       if (nd->flags & LOOKUP_EXCL) {
-               d_instantiate(dentry, NULL);
-               goto out;
        }
 
-       open_flags = nd->intent.open.flags;
-       attr.ia_valid = ATTR_OPEN;
-
-       ctx = create_nfs_open_context(dentry, open_flags);
-       res = ERR_CAST(ctx);
-       if (IS_ERR(ctx))
-               goto out;
+       if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
+               return -ENAMETOOLONG;
 
-       if (nd->flags & LOOKUP_CREATE) {
-               attr.ia_mode = nd->intent.open.create_mode;
+       if (open_flags & O_CREAT) {
                attr.ia_valid |= ATTR_MODE;
-               attr.ia_mode &= ~current_umask();
-       } else
-               open_flags &= ~(O_EXCL | O_CREAT);
-
+               attr.ia_mode = mode & ~current_umask();
+       }
        if (open_flags & O_TRUNC) {
                attr.ia_valid |= ATTR_SIZE;
                attr.ia_size = 0;
        }
 
-       /* Open the file on the server */
+       ctx = create_nfs_open_context(dentry, open_flags);
+       err = PTR_ERR(ctx);
+       if (IS_ERR(ctx))
+               goto out;
+
        nfs_block_sillyrename(dentry->d_parent);
        inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
+       d_drop(dentry);
        if (IS_ERR(inode)) {
                nfs_unblock_sillyrename(dentry->d_parent);
                put_nfs_open_context(ctx);
-               switch (PTR_ERR(inode)) {
-                       /* Make a negative dentry */
-                       case -ENOENT:
-                               d_add(dentry, NULL);
-                               res = NULL;
-                               goto out;
-                       /* This turned out not to be a regular file */
-                       case -EISDIR:
-                       case -ENOTDIR:
+               err = PTR_ERR(inode);
+               switch (err) {
+               case -ENOENT:
+                       d_add(dentry, NULL);
+                       break;
+               case -EISDIR:
+               case -ENOTDIR:
+                       goto no_open;
+               case -ELOOP:
+                       if (!(open_flags & O_NOFOLLOW))
                                goto no_open;
-                       case -ELOOP:
-                               if (!(nd->intent.open.flags & O_NOFOLLOW))
-                                       goto no_open;
+                       break;
                        /* case -EINVAL: */
-                       default:
-                               res = ERR_CAST(inode);
-                               goto out;
+               default:
+                       break;
                }
+               goto out;
        }
        res = d_add_unique(dentry, inode);
-       nfs_unblock_sillyrename(dentry->d_parent);
-       if (res != NULL) {
-               dput(ctx->dentry);
-               ctx->dentry = dget(res);
+       if (res != NULL)
                dentry = res;
-       }
-       err = nfs_intent_set_file(nd, ctx);
-       if (err < 0) {
-               if (res != NULL)
-                       dput(res);
-               return ERR_PTR(err);
-       }
-out:
+
+       nfs_unblock_sillyrename(dentry->d_parent);
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-       return res;
+
+       err = nfs_finish_open(ctx, dentry, file, open_flags, opened);
+
+       dput(res);
+out:
+       return err;
+
 no_open:
-       return nfs_lookup(dir, dentry, nd);
+       res = nfs_lookup(dir, dentry, 0);
+       err = PTR_ERR(res);
+       if (IS_ERR(res))
+               goto out;
+
+       return finish_no_open(file, res);
 }
 
-static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct dentry *parent = NULL;
        struct inode *inode;
        struct inode *dir;
-       int openflags, ret = 0;
+       int ret = 0;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
-       inode = dentry->d_inode;
-       if (!is_atomic_open(nd) || d_mountpoint(dentry))
+       if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
+               goto no_open;
+       if (d_mountpoint(dentry))
                goto no_open;
 
+       inode = dentry->d_inode;
        parent = dget_parent(dentry);
        dir = parent->d_inode;
 
@@ -1540,7 +1513,7 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
         * optimize away revalidation of negative dentries.
         */
        if (inode == NULL) {
-               if (!nfs_neg_need_reval(dir, dentry, nd))
+               if (!nfs_neg_need_reval(dir, dentry, flags))
                        ret = 1;
                goto out;
        }
@@ -1548,9 +1521,8 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
        /* NFS only supports OPEN on regular files */
        if (!S_ISREG(inode->i_mode))
                goto no_open_dput;
-       openflags = nd->intent.open.flags;
        /* We cannot do exclusive creation on a positive dentry */
-       if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
+       if (flags & LOOKUP_EXCL)
                goto no_open_dput;
 
        /* Let f_op->open() actually open (and revalidate) the file */
@@ -1563,48 +1535,7 @@ out:
 no_open_dput:
        dput(parent);
 no_open:
-       return nfs_lookup_revalidate(dentry, nd);
-}
-
-static int nfs_open_create(struct inode *dir, struct dentry *dentry,
-               umode_t mode, struct nameidata *nd)
-{
-       struct nfs_open_context *ctx = NULL;
-       struct iattr attr;
-       int error;
-       int open_flags = O_CREAT|O_EXCL;
-
-       dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
-                       dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
-
-       attr.ia_mode = mode;
-       attr.ia_valid = ATTR_MODE;
-
-       if (nd)
-               open_flags = nd->intent.open.flags;
-
-       ctx = create_nfs_open_context(dentry, open_flags);
-       error = PTR_ERR(ctx);
-       if (IS_ERR(ctx))
-               goto out_err_drop;
-
-       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx);
-       if (error != 0)
-               goto out_put_ctx;
-       if (nd) {
-               error = nfs_intent_set_file(nd, ctx);
-               if (error < 0)
-                       goto out_err;
-       } else {
-               put_nfs_open_context(ctx);
-       }
-       return 0;
-out_put_ctx:
-       put_nfs_open_context(ctx);
-out_err_drop:
-       d_drop(dentry);
-out_err:
-       return error;
+       return nfs_lookup_revalidate(dentry, flags);
 }
 
 #endif /* CONFIG_NFSV4 */
@@ -1658,11 +1589,11 @@ out_error:
  * reply path made it appear to have failed.
  */
 static int nfs_create(struct inode *dir, struct dentry *dentry,
-               umode_t mode, struct nameidata *nd)
+               umode_t mode, bool excl)
 {
        struct iattr attr;
+       int open_flags = excl ? O_CREAT | O_EXCL : O_CREAT;
        int error;
-       int open_flags = O_CREAT|O_EXCL;
 
        dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
@@ -1670,10 +1601,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry,
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
 
-       if (nd)
-               open_flags = nd->intent.open.flags;
-
-       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, NULL);
+       error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags);
        if (error != 0)
                goto out_err;
        return 0;
index 9a4cbfc85d81fd203efe4db51f8897eb6bf45185..48253372ab1d115def0b81f56b097db6e98a0f88 100644 (file)
@@ -484,6 +484,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
 
        list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
                if (!nfs_pageio_add_request(&desc, req)) {
+                       nfs_list_remove_request(req);
                        nfs_list_add_request(req, &failed);
                        spin_lock(cinfo.lock);
                        dreq->flags = 0;
@@ -494,8 +495,11 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
        }
        nfs_pageio_complete(&desc);
 
-       while (!list_empty(&failed))
+       while (!list_empty(&failed)) {
+               req = nfs_list_entry(failed.next);
+               nfs_list_remove_request(req);
                nfs_unlock_and_release_request(req);
+       }
 
        if (put_dreq(dreq))
                nfs_direct_write_complete(dreq, dreq->inode);
index 8abfb19bd3aa3b739611ce1f97025d643539b09c..a67990f90bd7d28bdea3310514e4a88275eadc14 100644 (file)
@@ -62,7 +62,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
                 */
                spin_lock(&sb->s_root->d_inode->i_lock);
                spin_lock(&sb->s_root->d_lock);
-               list_del_init(&sb->s_root->d_alias);
+               hlist_del_init(&sb->s_root->d_alias);
                spin_unlock(&sb->s_root->d_lock);
                spin_unlock(&sb->s_root->d_inode->i_lock);
        }
index 2292a0fd2bffd3b042b43e9dc4b607acbd0eb6ad..3187e24e8f78f41ffa3f78b55ccf42ff29d167f0 100644 (file)
@@ -314,7 +314,7 @@ static void nfs3_free_createdata(struct nfs3_createdata *data)
  */
 static int
 nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-                int flags, struct nfs_open_context *ctx)
+                int flags)
 {
        struct nfs3_createdata *data;
        umode_t mode = sattr->ia_mode;
index 15fc7e4664ed53206074df177efd74e30dd13521..c157b2089b475c22c046a15f293236f7725a4ee7 100644 (file)
@@ -2806,37 +2806,22 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page,
 }
 
 /*
- * Got race?
- * We will need to arrange for the VFS layer to provide an atomic open.
- * Until then, this create/open method is prone to inefficiency and race
- * conditions due to the lookup, create, and open VFS calls from sys_open()
- * placed on the wire.
- *
- * Given the above sorry state of affairs, I'm simply sending an OPEN.
- * The file will be opened again in the subsequent VFS open call
- * (nfs4_proc_file_open).
- *
- * The open for read will just hang around to be used by any process that
- * opens the file O_RDONLY. This will all be resolved with the VFS changes.
+ * This is just for mknod.  open(O_CREAT) will always do ->open_context().
  */
-
 static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-                 int flags, struct nfs_open_context *ctx)
+                int flags)
 {
-       struct dentry *de = dentry;
+       struct nfs_open_context *ctx;
        struct nfs4_state *state;
-       struct rpc_cred *cred = NULL;
-       fmode_t fmode = 0;
        int status = 0;
 
-       if (ctx != NULL) {
-               cred = ctx->cred;
-               de = ctx->dentry;
-               fmode = ctx->mode;
-       }
+       ctx = alloc_nfs_open_context(dentry, FMODE_READ);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+
        sattr->ia_mode &= ~current_umask();
-       state = nfs4_do_open(dir, de, fmode, flags, sattr, cred, NULL);
+       state = nfs4_do_open(dir, dentry, ctx->mode, flags, sattr, ctx->cred, NULL);
        d_drop(dentry);
        if (IS_ERR(state)) {
                status = PTR_ERR(state);
@@ -2844,11 +2829,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        }
        d_add(dentry, igrab(state->inode));
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
-       if (ctx != NULL)
-               ctx->state = state;
-       else
-               nfs4_close_sync(state, fmode);
+       ctx->state = state;
 out:
+       put_nfs_open_context(ctx);
        return status;
 }
 
index b47277baebab92930bee6c1fbac445fd8978a6b9..f50d3e8d6f2230a42cdc656b61004dcf62182dd2 100644 (file)
@@ -454,7 +454,10 @@ int objio_read_pagelist(struct nfs_read_data *rdata)
        objios->ios->done = _read_done;
        dprintk("%s: offset=0x%llx length=0x%x\n", __func__,
                rdata->args.offset, rdata->args.count);
-       return ore_read(objios->ios);
+       ret = ore_read(objios->ios);
+       if (unlikely(ret))
+               objio_free_result(&objios->oir);
+       return ret;
 }
 
 /*
@@ -486,8 +489,16 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
        struct nfs_write_data *wdata = objios->oir.rpcdata;
        struct address_space *mapping = wdata->header->inode->i_mapping;
        pgoff_t index = offset / PAGE_SIZE;
-       struct page *page = find_get_page(mapping, index);
+       struct page *page;
+       loff_t i_size = i_size_read(wdata->header->inode);
+
+       if (offset >= i_size) {
+               *uptodate = true;
+               dprintk("%s: g_zero_page index=0x%lx\n", __func__, index);
+               return ZERO_PAGE(0);
+       }
 
+       page = find_get_page(mapping, index);
        if (!page) {
                page = find_or_create_page(mapping, index, GFP_NOFS);
                if (unlikely(!page)) {
@@ -507,8 +518,10 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
 
 static void __r4w_put_page(void *priv, struct page *page)
 {
-       dprintk("%s: index=0x%lx\n", __func__, page->index);
-       page_cache_release(page);
+       dprintk("%s: index=0x%lx\n", __func__,
+               (page == ZERO_PAGE(0)) ? -1UL : page->index);
+       if (ZERO_PAGE(0) != page)
+               page_cache_release(page);
        return;
 }
 
@@ -539,8 +552,10 @@ int objio_write_pagelist(struct nfs_write_data *wdata, int how)
        dprintk("%s: offset=0x%llx length=0x%x\n", __func__,
                wdata->args.offset, wdata->args.count);
        ret = ore_write(objios->ios);
-       if (unlikely(ret))
+       if (unlikely(ret)) {
+               objio_free_result(&objios->oir);
                return ret;
+       }
 
        if (objios->sync)
                _write_done(objios->ios, objios);
index 617c7419a08ef5d0b107292bb626b84b99916b2d..4433806e116f9a4b26f605c4ef986a1633eb3efd 100644 (file)
@@ -259,7 +259,7 @@ static void nfs_free_createdata(const struct nfs_createdata *data)
 
 static int
 nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
-               int flags, struct nfs_open_context *ctx)
+               int flags)
 {
        struct nfs_createdata *data;
        struct rpc_message msg = {
index 906f09c7d842522f5defd230c997527b1d94c8e8..8b2a2977b720729f2a63a4d7bb8e5e4b7de5522e 100644 (file)
@@ -2419,7 +2419,7 @@ static struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type,
                sb_mntdata.mntflags |= MS_SYNCHRONOUS;
 
        /* Get a superblock - note that we may end up sharing one that already exists */
-       s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
+       s = sget(fs_type, compare_super, nfs_set_super, flags, &sb_mntdata);
        if (IS_ERR(s)) {
                mntroot = ERR_CAST(s);
                goto out_err_nosb;
@@ -2860,6 +2860,8 @@ static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 
        dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
+       mount_info->fill_super = nfs4_fill_super;
+
        export_path = data->nfs_server.export_path;
        data->nfs_server.export_path = "/";
        root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
index c8bd9c3be7f747410622fd1172b2c7243886f838..4700a0a929d72baeb0c86024a1c5051e6d19cab5 100644 (file)
@@ -745,7 +745,7 @@ __be32
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
                        int may_flags, struct file **filp)
 {
-       struct dentry   *dentry;
+       struct path     path;
        struct inode    *inode;
        int             flags = O_RDONLY|O_LARGEFILE;
        __be32          err;
@@ -762,8 +762,9 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
        if (err)
                goto out;
 
-       dentry = fhp->fh_dentry;
-       inode = dentry->d_inode;
+       path.mnt = fhp->fh_export->ex_path.mnt;
+       path.dentry = fhp->fh_dentry;
+       inode = path.dentry->d_inode;
 
        /* Disallow write access to files with the append-only bit set
         * or any access when mandatory locking enabled
@@ -792,8 +793,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
                else
                        flags = O_WRONLY|O_LARGEFILE;
        }
-       *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
-                           flags, current_cred());
+       *filp = dentry_open(&path, flags, current_cred());
        if (IS_ERR(*filp))
                host_err = PTR_ERR(*filp);
        else {
@@ -1329,7 +1329,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        err = 0;
        switch (type) {
        case S_IFREG:
-               host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+               host_err = vfs_create(dirp, dchild, iap->ia_mode, true);
                if (!host_err)
                        nfsd_check_ignore_resizing(iap);
                break;
@@ -1492,7 +1492,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                goto out;
        }
 
-       host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+       host_err = vfs_create(dirp, dchild, iap->ia_mode, true);
        if (host_err < 0) {
                fh_drop_write(fhp);
                goto out_nfserr;
index b72847988b78d96d99b7571d17fea769e463c6b0..1d0c0b84c5a319e61e24f04f3d643f9284b6cee6 100644 (file)
@@ -63,7 +63,7 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode)
  */
 
 static struct dentry *
-nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode;
        ino_t ino;
@@ -85,7 +85,7 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
  * with d_instantiate().
  */
 static int nilfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                       struct nameidata *nd)
+                       bool excl)
 {
        struct inode *inode;
        struct nilfs_transaction_info ti;
index 1099a76cee5962838841a9719a0758e4defcb2d3..d57c42f974ea3ccb78dfccccc34cbbedf9603004 100644 (file)
@@ -1288,7 +1288,8 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
                err = -EBUSY;
                goto failed;
        }
-       s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev);
+       s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, flags,
+                sd.bdev);
        mutex_unlock(&sd.bdev->bd_fsfreeze_mutex);
        if (IS_ERR(s)) {
                err = PTR_ERR(s);
@@ -1301,7 +1302,6 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
                s_new = true;
 
                /* New superblock instance created */
-               s->s_flags = flags;
                s->s_mode = mode;
                strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id));
                sb_set_blocksize(s, block_size(sd.bdev));
index 3568c8a8b1387aea2845d6998b2b7e6d1dc6dcb2..d43803669739df471e8e832ced4377f6f75ab015 100644 (file)
@@ -61,8 +61,6 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
 static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event)
 {
        int client_fd;
-       struct dentry *dentry;
-       struct vfsmount *mnt;
        struct file *new_file;
 
        pr_debug("%s: group=%p event=%p\n", __func__, group, event);
@@ -81,12 +79,10 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event)
         * we need a new file handle for the userspace program so it can read even if it was
         * originally opened O_WRONLY.
         */
-       dentry = dget(event->path.dentry);
-       mnt = mntget(event->path.mnt);
        /* it's possible this event was an overflow event.  in that case dentry and mnt
         * are NULL;  That's fine, just don't call dentry open */
-       if (dentry && mnt)
-               new_file = dentry_open(dentry, mnt,
+       if (event->path.dentry && event->path.mnt)
+               new_file = dentry_open(&event->path,
                                       group->fanotify_data.f_flags | FMODE_NONOTIFY,
                                       current_cred());
        else
index b39c5c161adb64bff0d33faa64f41d8f4a9942cd..6baadb5a84307d176cd87ad99f399992ddff9519 100644 (file)
@@ -52,6 +52,7 @@ void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
 void __fsnotify_update_child_dentry_flags(struct inode *inode)
 {
        struct dentry *alias;
+       struct hlist_node *p;
        int watched;
 
        if (!S_ISDIR(inode->i_mode))
@@ -63,7 +64,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
        spin_lock(&inode->i_lock);
        /* run all of the dentries associated with this inode.  Since this is a
         * directory, there damn well better only be one item on this list */
-       list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+       hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
                struct dentry *child;
 
                /* run all of the children of the original inode and fix their
index 358273e59aded3d416dea0f1e67627731d9d0d8f..436f36037e094577592576e71054a2cf350a29bb 100644 (file)
  * Locking: Caller must hold i_mutex on the directory.
  */
 static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
-               struct nameidata *nd)
+               unsigned int flags)
 {
        ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
        struct inode *dent_inode;
index e5ba348183321d133ab7f75c715b305dbed28a07..8db4b58b2e4b2e92a5e6fe42c7c71c657866c125 100644 (file)
@@ -49,14 +49,13 @@ void ocfs2_dentry_attach_gen(struct dentry *dentry)
 }
 
 
-static int ocfs2_dentry_revalidate(struct dentry *dentry,
-                                  struct nameidata *nd)
+static int ocfs2_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode;
        int ret = 0;    /* if all else fails, just return false */
        struct ocfs2_super *osb;
 
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = dentry->d_inode;
@@ -170,13 +169,11 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
                                      u64 parent_blkno,
                                      int skip_unhashed)
 {
-       struct list_head *p;
-       struct dentry *dentry = NULL;
+       struct hlist_node *p;
+       struct dentry *dentry;
 
        spin_lock(&inode->i_lock);
-       list_for_each(p, &inode->i_dentry) {
-               dentry = list_entry(p, struct dentry, d_alias);
-
+       hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
                spin_lock(&dentry->d_lock);
                if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
                        trace_ocfs2_find_local_alias(dentry->d_name.len,
@@ -184,16 +181,13 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
 
                        dget_dlock(dentry);
                        spin_unlock(&dentry->d_lock);
-                       break;
+                       spin_unlock(&inode->i_lock);
+                       return dentry;
                }
                spin_unlock(&dentry->d_lock);
-
-               dentry = NULL;
        }
-
        spin_unlock(&inode->i_lock);
-
-       return dentry;
+       return NULL;
 }
 
 DEFINE_SPINLOCK(dentry_attach_lock);
index e31d6ae013abba789b8d72591e8a460f6a8c7afc..83b6f98e0665433bda36a2f1d4f34a1ce7bec4cd 100644 (file)
@@ -526,7 +526,7 @@ bail:
 static int dlmfs_create(struct inode *dir,
                        struct dentry *dentry,
                        umode_t mode,
-                       struct nameidata *nd)
+                       bool excl)
 {
        int status = 0;
        struct inode *inode;
index 81a4cd22f80be84a06eac2b0fbf4348385d76262..4f7795fb5fc0b78a6f58d28f2de69356ff5e197d 100644 (file)
@@ -456,7 +456,7 @@ static void ocfs2_update_lock_stats(struct ocfs2_lock_res *res, int level,
        stats->ls_gets++;
        stats->ls_total += ktime_to_ns(kt);
        /* overflow */
-       if (unlikely(stats->ls_gets) == 0) {
+       if (unlikely(stats->ls_gets == 0)) {
                stats->ls_gets++;
                stats->ls_total = ktime_to_ns(kt);
        }
@@ -3932,6 +3932,8 @@ unqueue:
 static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
                                        struct ocfs2_lock_res *lockres)
 {
+       unsigned long flags;
+
        assert_spin_locked(&lockres->l_lock);
 
        if (lockres->l_flags & OCFS2_LOCK_FREEING) {
@@ -3945,21 +3947,22 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
 
        lockres_or_flags(lockres, OCFS2_LOCK_QUEUED);
 
-       spin_lock(&osb->dc_task_lock);
+       spin_lock_irqsave(&osb->dc_task_lock, flags);
        if (list_empty(&lockres->l_blocked_list)) {
                list_add_tail(&lockres->l_blocked_list,
                              &osb->blocked_lock_list);
                osb->blocked_lock_count++;
        }
-       spin_unlock(&osb->dc_task_lock);
+       spin_unlock_irqrestore(&osb->dc_task_lock, flags);
 }
 
 static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
 {
        unsigned long processed;
+       unsigned long flags;
        struct ocfs2_lock_res *lockres;
 
-       spin_lock(&osb->dc_task_lock);
+       spin_lock_irqsave(&osb->dc_task_lock, flags);
        /* grab this early so we know to try again if a state change and
         * wake happens part-way through our work  */
        osb->dc_work_sequence = osb->dc_wake_sequence;
@@ -3972,38 +3975,40 @@ static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb)
                                     struct ocfs2_lock_res, l_blocked_list);
                list_del_init(&lockres->l_blocked_list);
                osb->blocked_lock_count--;
-               spin_unlock(&osb->dc_task_lock);
+               spin_unlock_irqrestore(&osb->dc_task_lock, flags);
 
                BUG_ON(!processed);
                processed--;
 
                ocfs2_process_blocked_lock(osb, lockres);
 
-               spin_lock(&osb->dc_task_lock);
+               spin_lock_irqsave(&osb->dc_task_lock, flags);
        }
-       spin_unlock(&osb->dc_task_lock);
+       spin_unlock_irqrestore(&osb->dc_task_lock, flags);
 }
 
 static int ocfs2_downconvert_thread_lists_empty(struct ocfs2_super *osb)
 {
        int empty = 0;
+       unsigned long flags;
 
-       spin_lock(&osb->dc_task_lock);
+       spin_lock_irqsave(&osb->dc_task_lock, flags);
        if (list_empty(&osb->blocked_lock_list))
                empty = 1;
 
-       spin_unlock(&osb->dc_task_lock);
+       spin_unlock_irqrestore(&osb->dc_task_lock, flags);
        return empty;
 }
 
 static int ocfs2_downconvert_thread_should_wake(struct ocfs2_super *osb)
 {
        int should_wake = 0;
+       unsigned long flags;
 
-       spin_lock(&osb->dc_task_lock);
+       spin_lock_irqsave(&osb->dc_task_lock, flags);
        if (osb->dc_work_sequence != osb->dc_wake_sequence)
                should_wake = 1;
-       spin_unlock(&osb->dc_task_lock);
+       spin_unlock_irqrestore(&osb->dc_task_lock, flags);
 
        return should_wake;
 }
@@ -4033,10 +4038,12 @@ static int ocfs2_downconvert_thread(void *arg)
 
 void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb)
 {
-       spin_lock(&osb->dc_task_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&osb->dc_task_lock, flags);
        /* make sure the voting thread gets a swipe at whatever changes
         * the caller may have made to the voting state */
        osb->dc_wake_sequence++;
-       spin_unlock(&osb->dc_task_lock);
+       spin_unlock_irqrestore(&osb->dc_task_lock, flags);
        wake_up(&osb->dc_event);
 }
index 2f5b92ef0e533146007b49d21dd705a242125dc5..70b5863a2d64e05cde6474bd387112f3b470b5e7 100644 (file)
@@ -923,8 +923,6 @@ out_unlock:
 
        ocfs2_inode_unlock(inode, 0);
 out:
-       if (ret && ret != -ENXIO)
-               ret = -ENXIO;
        return ret;
 }
 
index 061591a3ab08a673d73544e819e7b7fd19b2689a..7602783d7f41c9a01827f16446da43e036e6a7cb 100644 (file)
@@ -1950,7 +1950,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
        if (ret < 0)
                mlog_errno(ret);
 
-       if (file->f_flags & O_SYNC)
+       if (file && (file->f_flags & O_SYNC))
                handle->h_sync = 1;
 
        ocfs2_commit_trans(osb, handle);
@@ -2422,8 +2422,10 @@ out_dio:
                unaligned_dio = 0;
        }
 
-       if (unaligned_dio)
+       if (unaligned_dio) {
+               ocfs2_iocb_clear_unaligned_aio(iocb);
                atomic_dec(&OCFS2_I(inode)->ip_unaligned_aio);
+       }
 
 out:
        if (rw_level != -1)
index 9f39c640cddf2076b951295dde5ef68217b26452..f1fd0741162b63baeaed44d6f4118a23df7c3c32 100644 (file)
@@ -98,7 +98,7 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
 #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
 
 static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        int status;
        u64 blkno;
@@ -618,7 +618,7 @@ static int ocfs2_mkdir(struct inode *dir,
 static int ocfs2_create(struct inode *dir,
                        struct dentry *dentry,
                        umode_t mode,
-                       struct nameidata *nd)
+                       bool excl)
 {
        int ret;
 
index 92fcd575775a0d1123e902b8499cd1b26cd52aab..0a86e302655f3384435ab4843fad50b6bf1a7cae 100644 (file)
@@ -399,8 +399,6 @@ int ocfs2_global_read_info(struct super_block *sb, int type)
                              msecs_to_jiffies(oinfo->dqi_syncms));
 
 out_err:
-       if (status)
-               mlog_errno(status);
        return status;
 out_unlock:
        ocfs2_unlock_global_qf(oinfo, 0);
index f00576ec320f26384a021d8cecab6fbcde93dd6a..fb5b3ff79dc6c232161fd89e35d4a23079a62a74 100644 (file)
@@ -285,13 +285,13 @@ static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 }
 
 static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        return omfs_add_node(dir, dentry, mode | S_IFREG);
 }
 
 static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
-                                 struct nameidata *nd)
+                                 unsigned int flags)
 {
        struct buffer_head *bh;
        struct inode *inode = NULL;
index d6c79a0dffc7b0827b09562e11fa0f610af5657d..1e914b397e129f311875eb15d0c7679ace93aa3e 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -397,10 +397,10 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
 {
        struct file *file;
        struct inode *inode;
-       int error;
+       int error, fput_needed;
 
        error = -EBADF;
-       file = fget(fd);
+       file = fget_raw_light(fd, &fput_needed);
        if (!file)
                goto out;
 
@@ -414,7 +414,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
        if (!error)
                set_fs_pwd(current->fs, &file->f_path);
 out_putf:
-       fput(file);
+       fput_light(file, fput_needed);
 out:
        return error;
 }
@@ -537,25 +537,6 @@ static int chown_common(struct path *path, uid_t user, gid_t group)
        return error;
 }
 
-SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
-{
-       struct path path;
-       int error;
-
-       error = user_path(filename, &path);
-       if (error)
-               goto out;
-       error = mnt_want_write(path.mnt);
-       if (error)
-               goto out_release;
-       error = chown_common(&path, user, group);
-       mnt_drop_write(path.mnt);
-out_release:
-       path_put(&path);
-out:
-       return error;
-}
-
 SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
                gid_t, group, int, flag)
 {
@@ -583,23 +564,15 @@ out:
        return error;
 }
 
-SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group)
+SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group)
 {
-       struct path path;
-       int error;
+       return sys_fchownat(AT_FDCWD, filename, user, group, 0);
+}
 
-       error = user_lpath(filename, &path);
-       if (error)
-               goto out;
-       error = mnt_want_write(path.mnt);
-       if (error)
-               goto out_release;
-       error = chown_common(&path, user, group);
-       mnt_drop_write(path.mnt);
-out_release:
-       path_put(&path);
-out:
-       return error;
+SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group)
+{
+       return sys_fchownat(AT_FDCWD, filename, user, group,
+                           AT_SYMLINK_NOFOLLOW);
 }
 
 SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
@@ -667,10 +640,9 @@ int open_check_o_direct(struct file *f)
        return 0;
 }
 
-static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
-                                  struct file *f,
-                                  int (*open)(struct inode *, struct file *),
-                                  const struct cred *cred)
+static int do_dentry_open(struct file *f,
+                         int (*open)(struct inode *, struct file *),
+                         const struct cred *cred)
 {
        static const struct file_operations empty_fops = {};
        struct inode *inode;
@@ -682,9 +654,9 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
        if (unlikely(f->f_flags & O_PATH))
                f->f_mode = FMODE_PATH;
 
-       inode = dentry->d_inode;
+       inode = f->f_path.dentry->d_inode;
        if (f->f_mode & FMODE_WRITE) {
-               error = __get_file_write_access(inode, mnt);
+               error = __get_file_write_access(inode, f->f_path.mnt);
                if (error)
                        goto cleanup_file;
                if (!special_file(inode->i_mode))
@@ -692,14 +664,12 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
        }
 
        f->f_mapping = inode->i_mapping;
-       f->f_path.dentry = dentry;
-       f->f_path.mnt = mnt;
        f->f_pos = 0;
        file_sb_list_add(f, inode->i_sb);
 
        if (unlikely(f->f_mode & FMODE_PATH)) {
                f->f_op = &empty_fops;
-               return f;
+               return 0;
        }
 
        f->f_op = fops_get(inode->i_fop);
@@ -726,10 +696,11 @@ static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 
        file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
 
-       return f;
+       return 0;
 
 cleanup_all:
        fops_put(f->f_op);
+       file_sb_list_del(f);
        if (f->f_mode & FMODE_WRITE) {
                put_write_access(inode);
                if (!special_file(inode->i_mode)) {
@@ -740,124 +711,62 @@ cleanup_all:
                         * here, so just reset the state.
                         */
                        file_reset_write(f);
-                       mnt_drop_write(mnt);
+                       mnt_drop_write(f->f_path.mnt);
                }
        }
-       file_sb_list_del(f);
-       f->f_path.dentry = NULL;
-       f->f_path.mnt = NULL;
 cleanup_file:
-       dput(dentry);
-       mntput(mnt);
-       return ERR_PTR(error);
-}
-
-static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
-                               struct file *f,
-                               int (*open)(struct inode *, struct file *),
-                               const struct cred *cred)
-{
-       struct file *res = do_dentry_open(dentry, mnt, f, open, cred);
-       if (!IS_ERR(res)) {
-               int error = open_check_o_direct(f);
-               if (error) {
-                       fput(res);
-                       res = ERR_PTR(error);
-               }
-       } else {
-               put_filp(f);
-       }
-       return res;
+       path_put(&f->f_path);
+       f->f_path.mnt = NULL;
+       f->f_path.dentry = NULL;
+       return error;
 }
 
 /**
- * lookup_instantiate_filp - instantiates the open intent filp
- * @nd: pointer to nameidata
+ * finish_open - finish opening a file
+ * @od: opaque open data
  * @dentry: pointer to dentry
  * @open: open callback
  *
- * Helper for filesystems that want to use lookup open intents and pass back
- * a fully instantiated struct file to the caller.
- * This function is meant to be called from within a filesystem's
- * lookup method.
- * Beware of calling it for non-regular files! Those ->open methods might block
- * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
- * leading to a deadlock, as nobody can open that fifo anymore, because
- * another process to open fifo will block on locked parent when doing lookup).
- * Note that in case of error, nd->intent.open.file is destroyed, but the
- * path information remains valid.
+ * This can be used to finish opening a file passed to i_op->atomic_open().
+ *
  * If the open callback is set to NULL, then the standard f_op->open()
  * filesystem callback is substituted.
  */
-struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
-               int (*open)(struct inode *, struct file *))
+int finish_open(struct file *file, struct dentry *dentry,
+               int (*open)(struct inode *, struct file *),
+               int *opened)
 {
-       const struct cred *cred = current_cred();
+       int error;
+       BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
 
-       if (IS_ERR(nd->intent.open.file))
-               goto out;
-       if (IS_ERR(dentry))
-               goto out_err;
-       nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
-                                            nd->intent.open.file,
-                                            open, cred);
-out:
-       return nd->intent.open.file;
-out_err:
-       release_open_intent(nd);
-       nd->intent.open.file = ERR_CAST(dentry);
-       goto out;
+       mntget(file->f_path.mnt);
+       file->f_path.dentry = dget(dentry);
+
+       error = do_dentry_open(file, open, current_cred());
+       if (!error)
+               *opened |= FILE_OPENED;
+
+       return error;
 }
-EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
+EXPORT_SYMBOL(finish_open);
 
 /**
- * nameidata_to_filp - convert a nameidata to an open filp.
- * @nd: pointer to nameidata
- * @flags: open flags
+ * finish_no_open - finish ->atomic_open() without opening the file
+ *
+ * @od: opaque open data
+ * @dentry: dentry or NULL (as returned from ->lookup())
  *
- * Note that this function destroys the original nameidata
+ * This can be used to set the result of a successful lookup in ->atomic_open().
+ * The filesystem's atomic_open() method shall return NULL after calling this.
  */
-struct file *nameidata_to_filp(struct nameidata *nd)
+int finish_no_open(struct file *file, struct dentry *dentry)
 {
-       const struct cred *cred = current_cred();
-       struct file *filp;
-
-       /* Pick up the filp from the open intent */
-       filp = nd->intent.open.file;
-
-       /* Has the filesystem initialised the file for us? */
-       if (filp->f_path.dentry != NULL) {
-               nd->intent.open.file = NULL;
-       } else {
-               struct file *res;
-
-               path_get(&nd->path);
-               res = do_dentry_open(nd->path.dentry, nd->path.mnt,
-                                    filp, NULL, cred);
-               if (!IS_ERR(res)) {
-                       int error;
-
-                       nd->intent.open.file = NULL;
-                       BUG_ON(res != filp);
-
-                       error = open_check_o_direct(filp);
-                       if (error) {
-                               fput(filp);
-                               filp = ERR_PTR(error);
-                       }
-               } else {
-                       /* Allow nd->intent.open.file to be recycled */
-                       filp = res;
-               }
-       }
-       return filp;
+       file->f_path.dentry = dentry;
+       return 1;
 }
+EXPORT_SYMBOL(finish_no_open);
 
-/*
- * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an
- * error.
- */
-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
+struct file *dentry_open(const struct path *path, int flags,
                         const struct cred *cred)
 {
        int error;
@@ -866,18 +775,28 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
        validate_creds(cred);
 
        /* We must always pass in a valid mount pointer. */
-       BUG_ON(!mnt);
+       BUG_ON(!path->mnt);
 
        error = -ENFILE;
        f = get_empty_filp();
-       if (f == NULL) {
-               dput(dentry);
-               mntput(mnt);
+       if (f == NULL)
                return ERR_PTR(error);
-       }
 
        f->f_flags = flags;
-       return __dentry_open(dentry, mnt, f, NULL, cred);
+       f->f_path = *path;
+       path_get(&f->f_path);
+       error = do_dentry_open(f, NULL, cred);
+       if (!error) {
+               error = open_check_o_direct(f);
+               if (error) {
+                       fput(f);
+                       f = ERR_PTR(error);
+               }
+       } else { 
+               put_filp(f);
+               f = ERR_PTR(error);
+       }
+       return f;
 }
 EXPORT_SYMBOL(dentry_open);
 
index bc49c975d501bad147ee9ac64fdafc5579de6d01..4a3477949bca6da23a13161708e0ee7168fdb654 100644 (file)
@@ -170,13 +170,13 @@ static const struct file_operations openprom_operations = {
        .llseek         = generic_file_llseek,
 };
 
-static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int);
 
 static const struct inode_operations openprom_inode_operations = {
        .lookup         = openpromfs_lookup,
 };
 
-static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        struct op_inode_info *ent_oi, *oi = OP_I(dir);
        struct device_node *dp, *child;
index bed378db075813350362c39f423d1b4335240bfa..3e000a51ac0d09556d184d26422a91d0bc4c0ff9 100644 (file)
@@ -237,8 +237,9 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry,
 
                source =  get_source(m, prev_dest_mnt, prev_src_mnt, &type);
 
-               if (!(child = copy_tree(source, source->mnt.mnt_root, type))) {
-                       ret = -ENOMEM;
+               child = copy_tree(source, source->mnt.mnt_root, type);
+               if (IS_ERR(child)) {
+                       ret = PTR_ERR(child);
                        list_splice(tree_list, tmp_list.prev);
                        goto out;
                }
index 437195f204e14e908bdda87ace0e8b0ce81efb21..2772208338f811c6b5d5bc067c490fe8725ba3cb 100644 (file)
@@ -1427,16 +1427,19 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
 static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
+       struct path path;
        int error = -EACCES;
 
-       /* We don't need a base pointer in the /proc filesystem */
-       path_put(&nd->path);
-
        /* Are we allowed to snoop on the tasks file descriptors? */
        if (!proc_fd_access_allowed(inode))
                goto out;
 
-       error = PROC_I(inode)->op.proc_get_link(dentry, &nd->path);
+       error = PROC_I(inode)->op.proc_get_link(dentry, &path);
+       if (error)
+               goto out;
+
+       nd_jump_link(nd, &path);
+       return NULL;
 out:
        return ERR_PTR(error);
 }
@@ -1601,13 +1604,13 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
  * made this apply to all per process world readable and executable
  * directories.
  */
-int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
+int pid_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode;
        struct task_struct *task;
        const struct cred *cred;
 
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = dentry->d_inode;
@@ -1781,7 +1784,7 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
        return proc_fd_info(dentry->d_inode, path, NULL);
 }
 
-static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct inode *inode;
        struct task_struct *task;
@@ -1789,7 +1792,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct files_struct *files;
        const struct cred *cred;
 
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        inode = dentry->d_inode;
@@ -1868,7 +1871,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
        d_set_d_op(dentry, &tid_fd_dentry_operations);
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
-       if (tid_fd_revalidate(dentry, NULL))
+       if (tid_fd_revalidate(dentry, 0))
                error = NULL;
 
  out:
@@ -1956,7 +1959,7 @@ out_no_task:
 }
 
 static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
-                                   struct nameidata *nd)
+                                   unsigned int flags)
 {
        return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
 }
@@ -2003,7 +2006,7 @@ static int dname_to_vma_addr(struct dentry *dentry,
        return 0;
 }
 
-static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        unsigned long vm_start, vm_end;
        bool exact_vma_exists = false;
@@ -2013,7 +2016,7 @@ static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd)
        struct inode *inode;
        int status = 0;
 
-       if (nd && nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        if (!capable(CAP_SYS_ADMIN)) {
@@ -2145,7 +2148,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
 }
 
 static struct dentry *proc_map_files_lookup(struct inode *dir,
-               struct dentry *dentry, struct nameidata *nd)
+               struct dentry *dentry, unsigned int flags)
 {
        unsigned long vm_start, vm_end;
        struct vm_area_struct *vma;
@@ -2371,7 +2374,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
        d_set_d_op(dentry, &tid_fd_dentry_operations);
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
-       if (tid_fd_revalidate(dentry, NULL))
+       if (tid_fd_revalidate(dentry, 0))
                error = NULL;
 
  out:
@@ -2380,7 +2383,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
 
 static struct dentry *proc_lookupfdinfo(struct inode *dir,
                                        struct dentry *dentry,
-                                       struct nameidata *nd)
+                                       unsigned int flags)
 {
        return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
 }
@@ -2430,7 +2433,7 @@ static struct dentry *proc_pident_instantiate(struct inode *dir,
        d_set_d_op(dentry, &pid_dentry_operations);
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
+       if (pid_revalidate(dentry, 0))
                error = NULL;
 out:
        return error;
@@ -2630,7 +2633,7 @@ static const struct file_operations proc_attr_dir_operations = {
 };
 
 static struct dentry *proc_attr_dir_lookup(struct inode *dir,
-                               struct dentry *dentry, struct nameidata *nd)
+                               struct dentry *dentry, unsigned int flags)
 {
        return proc_pident_lookup(dir, dentry,
                                  attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
@@ -3114,7 +3117,8 @@ static const struct file_operations proc_tgid_base_operations = {
        .llseek         = default_llseek,
 };
 
-static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
        return proc_pident_lookup(dir, dentry,
                                  tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
 }
@@ -3237,13 +3241,13 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
 
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
+       if (pid_revalidate(dentry, 0))
                error = NULL;
 out:
        return error;
 }
 
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
        struct dentry *result;
        struct task_struct *task;
@@ -3470,7 +3474,8 @@ static int proc_tid_base_readdir(struct file * filp,
                                   tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
 }
 
-static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
        return proc_pident_lookup(dir, dentry,
                                  tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
 }
@@ -3508,13 +3513,13 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
 
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
+       if (pid_revalidate(dentry, 0))
                error = NULL;
 out:
        return error;
 }
 
-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
 {
        struct dentry *result = ERR_PTR(-ENOENT);
        struct task_struct *task;
index 2edf34f2eb61136972e12e79714e36e4197e4ad8..b3647fe6a60870e55f36710497fd9dff583963ee 100644 (file)
@@ -446,7 +446,7 @@ out_unlock:
 }
 
 struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
-               struct nameidata *nd)
+               unsigned int flags)
 {
        return proc_lookup_de(PDE(dir), dir, dentry);
 }
index eca4aca5b6e227c11bb13c100deac3861b747a44..e1167a1c9126ee5f6a91971fec50ff3eaa79cce4 100644 (file)
@@ -106,7 +106,7 @@ void pde_users_dec(struct proc_dir_entry *pde);
 
 extern spinlock_t proc_subdir_lock;
 
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *);
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int);
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
 unsigned long task_vsize(struct mm_struct *);
 unsigned long task_statm(struct mm_struct *,
@@ -132,7 +132,7 @@ int proc_remount(struct super_block *sb, int *flags, char *data);
  * of the /proc/<pid> subdirectories.
  */
 int proc_readdir(struct file *, void *, filldir_t);
-struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
+struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int);
 
 
 
@@ -142,7 +142,7 @@ typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
 int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
        const char *name, int len,
        instantiate_t instantiate, struct task_struct *task, const void *ptr);
-int pid_revalidate(struct dentry *dentry, struct nameidata *nd);
+int pid_revalidate(struct dentry *dentry, unsigned int flags);
 struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task);
 extern const struct dentry_operations pid_dentry_operations;
 int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
index 0d9e23a39e495f0d6dd0a69d0f84aaa05faef9b5..b178ed733c3698a0ad2fcf49def0727b9fc135f6 100644 (file)
@@ -56,7 +56,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
        d_set_d_op(dentry, &pid_dentry_operations);
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
+       if (pid_revalidate(dentry, 0))
                error = NULL;
 out:
        return error;
@@ -140,7 +140,7 @@ const struct file_operations proc_ns_dir_operations = {
 };
 
 static struct dentry *proc_ns_dir_lookup(struct inode *dir,
-                               struct dentry *dentry, struct nameidata *nd)
+                               struct dentry *dentry, unsigned int flags)
 {
        struct dentry *error;
        struct task_struct *task = get_proc_task(dir);
index 06e1cc17caf6a8315c142397dad8ff1ff3d9ec75..fe72cd073dea8080becd6018ae89c76a4b83fe9f 100644 (file)
@@ -119,7 +119,7 @@ static struct net *get_proc_task_net(struct inode *dir)
 }
 
 static struct dentry *proc_tgid_net_lookup(struct inode *dir,
-               struct dentry *dentry, struct nameidata *nd)
+               struct dentry *dentry, unsigned int flags)
 {
        struct dentry *de;
        struct net *net;
index 3476bca8f7af93392539e28b14aeaf9b40c457a0..dfafeb2b05a0e2ddc5481b2b2a4f445ec8086a0e 100644 (file)
@@ -433,7 +433,7 @@ static struct ctl_table_header *grab_header(struct inode *inode)
 }
 
 static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
-                                       struct nameidata *nd)
+                                       unsigned int flags)
 {
        struct ctl_table_header *head = grab_header(dir);
        struct ctl_table_header *h = NULL;
@@ -794,9 +794,9 @@ static const struct inode_operations proc_sys_dir_operations = {
        .getattr        = proc_sys_getattr,
 };
 
-static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int proc_sys_revalidate(struct dentry *dentry, unsigned int flags)
 {
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
        return !PROC_I(dentry->d_inode)->sysctl->unregistering;
 }
index 7c30fce037c0e9cbf6d848aeb7cc1f8c25a13e83..9a2d9fd7cadd2acde77a4e00615f9bbafefc8d96 100644 (file)
@@ -111,7 +111,7 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
                options = data;
        }
 
-       sb = sget(fs_type, proc_test_super, proc_set_super, ns);
+       sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
        if (IS_ERR(sb))
                return ERR_CAST(sb);
 
@@ -121,7 +121,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
        }
 
        if (!sb->s_root) {
-               sb->s_flags = flags;
                err = proc_fill_super(sb);
                if (err) {
                        deactivate_locked_super(sb);
@@ -200,13 +199,12 @@ static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
        return 0;
 }
 
-static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
 {
-       if (!proc_lookup(dir, dentry, nd)) {
+       if (!proc_lookup(dir, dentry, flags))
                return NULL;
-       }
        
-       return proc_pid_lookup(dir, dentry, nd);
+       return proc_pid_lookup(dir, dentry, flags);
 }
 
 static int proc_root_readdir(struct file * filp,
index 5e289a7cbad17d8547458f1d8b2526f2e85e5cb9..5fe34c355e85e9bb7175cbfb2367e5c49928837a 100644 (file)
@@ -17,7 +17,7 @@
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
-       struct proc_mounts *p = file->private_data;
+       struct proc_mounts *p = proc_mounts(file->private_data);
        struct mnt_namespace *ns = p->ns;
        unsigned res = POLLIN | POLLRDNORM;
 
@@ -121,7 +121,7 @@ out:
 
 static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
 {
-       struct proc_mounts *p = m->private;
+       struct proc_mounts *p = proc_mounts(m);
        struct mount *r = real_mount(mnt);
        struct super_block *sb = mnt->mnt_sb;
        struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
@@ -268,7 +268,6 @@ static int mounts_open_common(struct inode *inode, struct file *file,
        if (ret)
                goto err_free;
 
-       p->m.private = p;
        p->ns = ns;
        p->root = root;
        p->m.poll_event = ns->event;
@@ -288,7 +287,7 @@ static int mounts_open_common(struct inode *inode, struct file *file,
 
 static int mounts_release(struct inode *inode, struct file *file)
 {
-       struct proc_mounts *p = file->private_data;
+       struct proc_mounts *p = proc_mounts(file->private_data);
        path_put(&p->root);
        put_mnt_ns(p->ns);
        return seq_release(inode, file);
index a512c0b30e8e72a853a5c7711217b2c56778a62f..d024505ba007549239f055f723c6fe13d8d23828 100644 (file)
@@ -95,7 +95,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
        return NULL;
 }
 
-struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        int ino;
        struct qnx4_inode_entry *de;
index 244d4620189b3daf49708ad9d08b861e7106dd6d..34e2d329c97e057f330d83f835fd111f931607be 100644 (file)
@@ -23,7 +23,7 @@ struct qnx4_inode_info {
 };
 
 extern struct inode *qnx4_iget(struct super_block *, unsigned long);
-extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd);
+extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
 
index e44012dc56458a9e379695a5ee36fe44a7f768fc..2049c814bda475a7e02e9e4411d54cc74f304660 100644 (file)
@@ -622,7 +622,6 @@ static struct inode *qnx6_alloc_inode(struct super_block *sb)
 static void qnx6_i_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
-       INIT_LIST_HEAD(&inode->i_dentry);
        kmem_cache_free(qnx6_inode_cachep, QNX6_I(inode));
 }
 
index 8a97289e04ad18204537535f90e1ab85eae9ac2f..0561326a94f5d48551d68be18dccbb8ffe59fd38 100644 (file)
@@ -13,7 +13,7 @@
 #include "qnx6.h"
 
 struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
-                               struct nameidata *nd)
+                               unsigned int flags)
 {
        unsigned ino;
        struct page *page;
index 6c5e02a0b6a8d9df7e0244493c3ba5c828457ec3..b00fcc960d374f28154b3efa9c7d9f8a4e5e7c88 100644 (file)
@@ -45,7 +45,7 @@ struct qnx6_inode_info {
 
 extern struct inode *qnx6_iget(struct super_block *sb, unsigned ino);
 extern struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry,
-                                       struct nameidata *nd);
+                                       unsigned int flags);
 
 #ifdef CONFIG_QNX6FS_DEBUG
 extern void qnx6_superblock_debug(struct qnx6_super_block *,
index 10cbe841cb7ecca3a823da92621ec3e614a2be09..d679fc48ef27bcb6e62ac10fb9de1ba2677d7fdd 100644 (file)
@@ -595,12 +595,14 @@ out:
 }
 EXPORT_SYMBOL(dquot_scan_active);
 
-int dquot_quota_sync(struct super_block *sb, int type, int wait)
+/* Write all dquot structures to quota files */
+int dquot_writeback_dquots(struct super_block *sb, int type)
 {
        struct list_head *dirty;
        struct dquot *dquot;
        struct quota_info *dqopt = sb_dqopt(sb);
        int cnt;
+       int err, ret = 0;
 
        mutex_lock(&dqopt->dqonoff_mutex);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -624,7 +626,9 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait)
                        atomic_inc(&dquot->dq_count);
                        spin_unlock(&dq_list_lock);
                        dqstats_inc(DQST_LOOKUPS);
-                       sb->dq_op->write_dquot(dquot);
+                       err = sb->dq_op->write_dquot(dquot);
+                       if (!ret && err)
+                               err = ret;
                        dqput(dquot);
                        spin_lock(&dq_list_lock);
                }
@@ -638,7 +642,21 @@ int dquot_quota_sync(struct super_block *sb, int type, int wait)
        dqstats_inc(DQST_SYNCS);
        mutex_unlock(&dqopt->dqonoff_mutex);
 
-       if (!wait || (dqopt->flags & DQUOT_QUOTA_SYS_FILE))
+       return ret;
+}
+EXPORT_SYMBOL(dquot_writeback_dquots);
+
+/* Write all dquot structures to disk and make them visible from userspace */
+int dquot_quota_sync(struct super_block *sb, int type)
+{
+       struct quota_info *dqopt = sb_dqopt(sb);
+       int cnt;
+       int ret;
+
+       ret = dquot_writeback_dquots(sb, type);
+       if (ret)
+               return ret;
+       if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
                return 0;
 
        /* This is not very clever (and fast) but currently I don't know about
index 9a391204ca278e4186300215ef521183af70eb68..c659f92298d3623eed8da9eb9d53c064dd917141 100644 (file)
@@ -47,7 +47,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
 static void quota_sync_one(struct super_block *sb, void *arg)
 {
        if (sb->s_qcop && sb->s_qcop->quota_sync)
-               sb->s_qcop->quota_sync(sb, *(int *)arg, 1);
+               sb->s_qcop->quota_sync(sb, *(int *)arg);
 }
 
 static int quota_sync_all(int type)
@@ -270,7 +270,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
        case Q_SYNC:
                if (!sb->s_qcop->quota_sync)
                        return -ENOSYS;
-               return sb->s_qcop->quota_sync(sb, type, 1);
+               return sb->s_qcop->quota_sync(sb, type);
        case Q_XQUOTAON:
        case Q_XQUOTAOFF:
        case Q_XQUOTARM:
index fbb0b478a346fbc77c854696c5e0e508760125ad..d5378d028589843e1cfef1efd5dba0b8cc4072cb 100644 (file)
@@ -110,6 +110,7 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 
                /* prevent the page from being discarded on memory pressure */
                SetPageDirty(page);
+               SetPageUptodate(page);
 
                unlock_page(page);
                put_page(page);
index a1fdabe21dec4e93a42bc101d6a32b480cc89c23..eab8c09d3801ca00db98687c49f22b58a633ccc8 100644 (file)
@@ -114,7 +114,7 @@ static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
        return retval;
 }
 
-static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
+static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
 {
        return ramfs_mknod(dir, dentry, mode | S_IFREG, 0);
 }
index c20614f86c01ed88ed36a65e9dfafdabfd3ba4d3..1adfb691e4f152444d8b7a080c1159057bbed9ad 100644 (file)
@@ -55,10 +55,11 @@ static loff_t lseek_execute(struct file *file, struct inode *inode,
  * @file:      file structure to seek on
  * @offset:    file offset to seek to
  * @origin:    type of seek
- * @size:      max size of file system
+ * @size:      max size of this file in file system
+ * @eof:       offset used for SEEK_END position
  *
  * This is a variant of generic_file_llseek that allows passing in a custom
- * file size.
+ * maximum file size and a custom EOF position, for e.g. hashed directories
  *
  * Synchronization:
  * SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms)
@@ -67,13 +68,13 @@ static loff_t lseek_execute(struct file *file, struct inode *inode,
  */
 loff_t
 generic_file_llseek_size(struct file *file, loff_t offset, int origin,
-               loff_t maxsize)
+               loff_t maxsize, loff_t eof)
 {
        struct inode *inode = file->f_mapping->host;
 
        switch (origin) {
        case SEEK_END:
-               offset += i_size_read(inode);
+               offset += eof;
                break;
        case SEEK_CUR:
                /*
@@ -99,7 +100,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int origin,
                 * In the generic case the entire file is data, so as long as
                 * offset isn't at the end of the file then the offset is data.
                 */
-               if (offset >= i_size_read(inode))
+               if (offset >= eof)
                        return -ENXIO;
                break;
        case SEEK_HOLE:
@@ -107,9 +108,9 @@ generic_file_llseek_size(struct file *file, loff_t offset, int origin,
                 * There is a virtual hole at the end of the file, so as long as
                 * offset isn't i_size or larger, return i_size.
                 */
-               if (offset >= i_size_read(inode))
+               if (offset >= eof)
                        return -ENXIO;
-               offset = i_size_read(inode);
+               offset = eof;
                break;
        }
 
@@ -132,7 +133,8 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
        struct inode *inode = file->f_mapping->host;
 
        return generic_file_llseek_size(file, offset, origin,
-                                       inode->i_sb->s_maxbytes);
+                                       inode->i_sb->s_maxbytes,
+                                       i_size_read(inode));
 }
 EXPORT_SYMBOL(generic_file_llseek);
 
index 84e8a69cee9d3882d5b7552c6cfdbc3459baf8e5..8567fb847601ceac1e8a7a6b6048061d4797352d 100644 (file)
@@ -322,7 +322,7 @@ static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen,
 }
 
 static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
-                                     struct nameidata *nd)
+                                     unsigned int flags)
 {
        int retval;
        int lock_depth;
@@ -573,7 +573,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, umode_t mode)
 }
 
 static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                          struct nameidata *nd)
+                          bool excl)
 {
        int retval;
        struct inode *inode;
@@ -634,8 +634,8 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mod
        reiserfs_update_inode_transaction(inode);
        reiserfs_update_inode_transaction(dir);
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
 
       out_failed:
@@ -712,8 +712,8 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode
                goto out_failed;
        }
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
 
       out_failed:
@@ -800,8 +800,8 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        // the above add_entry did not update dir's stat data
        reiserfs_update_sd(&th, dir);
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        retval = journal_end(&th, dir->i_sb, jbegin_count);
 out_failed:
        reiserfs_write_unlock_once(dir->i_sb, lock_depth);
@@ -1096,8 +1096,8 @@ static int reiserfs_symlink(struct inode *parent_dir,
                goto out_failed;
        }
 
-       d_instantiate(dentry, inode);
        unlock_new_inode(inode);
+       d_instantiate(dentry, inode);
        retval = journal_end(&th, parent_dir->i_sb, jbegin_count);
       out_failed:
        reiserfs_write_unlock(parent_dir->i_sb);
index 2c1ade692cc840efbb50be597877fde71cb4780c..e60e87035bb3eac8ed3047b392dd5a71b13ee0c3 100644 (file)
@@ -403,7 +403,7 @@ static void *r_start(struct seq_file *m, loff_t * pos)
        if (l)
                return NULL;
 
-       if (IS_ERR(sget(&reiserfs_fs_type, test_sb, set_sb, s)))
+       if (IS_ERR(sget(&reiserfs_fs_type, test_sb, set_sb, 0, s)))
                return NULL;
 
        up_write(&s->s_umount);
index 651ce767b55d8241e283b3001d7fc9e6d803b317..7a37dabf5a968b7c8977c2028665f58554987912 100644 (file)
@@ -68,6 +68,11 @@ static int reiserfs_sync_fs(struct super_block *s, int wait)
 {
        struct reiserfs_transaction_handle th;
 
+       /*
+        * Writeback quota in non-journalled quota case - journalled quota has
+        * no dirty dquots
+        */
+       dquot_writeback_dquots(s, -1);
        reiserfs_write_lock(s);
        if (!journal_begin(&th, s, 1))
                if (!journal_end_sync(&th, s, 1))
index 46fc1c20a6b1c65ccd72a8f18106283b01197916..d319963aeb1171e755018f966a3e1bff776cacf3 100644 (file)
@@ -62,7 +62,7 @@
 static int xattr_create(struct inode *dir, struct dentry *dentry, int mode)
 {
        BUG_ON(!mutex_is_locked(&dir->i_mutex));
-       return dir->i_op->create(dir, dentry, mode, NULL);
+       return dir->i_op->create(dir, dentry, mode, true);
 }
 #endif
 
@@ -942,7 +942,7 @@ int reiserfs_permission(struct inode *inode, int mask)
        return generic_permission(inode, mask);
 }
 
-static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int xattr_hide_revalidate(struct dentry *dentry, unsigned int flags)
 {
        return -EPERM;
 }
index e64f6b5f7ae57f72d636a4b7f3f5a2c2e3839202..77c5f21739837753efdfed09e806e32d1376a219 100644 (file)
@@ -210,7 +210,7 @@ out:
  * look up an entry in a directory
  */
 static struct dentry *romfs_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        unsigned long offset, maxoff;
        struct inode *inode;
index c9f1318a3b820b363526576036c4894205552921..7bf08fa22ec9ab122bad5438a02bd78db6f1e885 100644 (file)
@@ -273,13 +273,16 @@ void spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
  * Check if we need to grow the arrays holding pages and partial page
  * descriptions.
  */
-int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
+int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
 {
-       if (pipe->buffers <= PIPE_DEF_BUFFERS)
+       unsigned int buffers = ACCESS_ONCE(pipe->buffers);
+
+       spd->nr_pages_max = buffers;
+       if (buffers <= PIPE_DEF_BUFFERS)
                return 0;
 
-       spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL);
-       spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL);
+       spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL);
+       spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL);
 
        if (spd->pages && spd->partial)
                return 0;
@@ -289,10 +292,9 @@ int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd)
        return -ENOMEM;
 }
 
-void splice_shrink_spd(struct pipe_inode_info *pipe,
-                      struct splice_pipe_desc *spd)
+void splice_shrink_spd(struct splice_pipe_desc *spd)
 {
-       if (pipe->buffers <= PIPE_DEF_BUFFERS)
+       if (spd->nr_pages_max <= PIPE_DEF_BUFFERS)
                return;
 
        kfree(spd->pages);
@@ -315,6 +317,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
        struct splice_pipe_desc spd = {
                .pages = pages,
                .partial = partial,
+               .nr_pages_max = PIPE_DEF_BUFFERS,
                .flags = flags,
                .ops = &page_cache_pipe_buf_ops,
                .spd_release = spd_release_page,
@@ -326,7 +329,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
        index = *ppos >> PAGE_CACHE_SHIFT;
        loff = *ppos & ~PAGE_CACHE_MASK;
        req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       nr_pages = min(req_pages, pipe->buffers);
+       nr_pages = min(req_pages, spd.nr_pages_max);
 
        /*
         * Lookup the (hopefully) full range of pages we need.
@@ -497,7 +500,7 @@ fill_it:
        if (spd.nr_pages)
                error = splice_to_pipe(pipe, &spd);
 
-       splice_shrink_spd(pipe, &spd);
+       splice_shrink_spd(&spd);
        return error;
 }
 
@@ -598,6 +601,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
        struct splice_pipe_desc spd = {
                .pages = pages,
                .partial = partial,
+               .nr_pages_max = PIPE_DEF_BUFFERS,
                .flags = flags,
                .ops = &default_pipe_buf_ops,
                .spd_release = spd_release_page,
@@ -608,8 +612,8 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
 
        res = -ENOMEM;
        vec = __vec;
-       if (pipe->buffers > PIPE_DEF_BUFFERS) {
-               vec = kmalloc(pipe->buffers * sizeof(struct iovec), GFP_KERNEL);
+       if (spd.nr_pages_max > PIPE_DEF_BUFFERS) {
+               vec = kmalloc(spd.nr_pages_max * sizeof(struct iovec), GFP_KERNEL);
                if (!vec)
                        goto shrink_ret;
        }
@@ -617,7 +621,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
        offset = *ppos & ~PAGE_CACHE_MASK;
        nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
-       for (i = 0; i < nr_pages && i < pipe->buffers && len; i++) {
+       for (i = 0; i < nr_pages && i < spd.nr_pages_max && len; i++) {
                struct page *page;
 
                page = alloc_page(GFP_USER);
@@ -665,7 +669,7 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
 shrink_ret:
        if (vec != __vec)
                kfree(vec);
-       splice_shrink_spd(pipe, &spd);
+       splice_shrink_spd(&spd);
        return res;
 
 err:
@@ -1614,6 +1618,7 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
        struct splice_pipe_desc spd = {
                .pages = pages,
                .partial = partial,
+               .nr_pages_max = PIPE_DEF_BUFFERS,
                .flags = flags,
                .ops = &user_page_pipe_buf_ops,
                .spd_release = spd_release_page,
@@ -1629,13 +1634,13 @@ static long vmsplice_to_pipe(struct file *file, const struct iovec __user *iov,
 
        spd.nr_pages = get_iovec_page_array(iov, nr_segs, spd.pages,
                                            spd.partial, false,
-                                           pipe->buffers);
+                                           spd.nr_pages_max);
        if (spd.nr_pages <= 0)
                ret = spd.nr_pages;
        else
                ret = splice_to_pipe(pipe, &spd);
 
-       splice_shrink_spd(pipe, &spd);
+       splice_shrink_spd(&spd);
        return ret;
 }
 
index abcc58f3c15266dd24b9533b4b1103d3514a0c3e..7834a517f7f422cfb9bc35f997e8c69e4e91e52d 100644 (file)
@@ -134,7 +134,7 @@ out:
 
 
 static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
-                                struct nameidata *nd)
+                                unsigned int flags)
 {
        const unsigned char *name = dentry->d_name.name;
        int len = dentry->d_name.len;
index cf001775617f5781ac4f43f5695ad7802c6b4524..c743fb3be4b8a45d8d99f9b757bfc44bbb949683 100644 (file)
@@ -105,11 +105,12 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc)
 /**
  *     alloc_super     -       create new superblock
  *     @type:  filesystem type superblock should belong to
+ *     @flags: the mount flags
  *
  *     Allocates and initializes a new &struct super_block.  alloc_super()
  *     returns a pointer new superblock or %NULL if allocation had failed.
  */
-static struct super_block *alloc_super(struct file_system_type *type)
+static struct super_block *alloc_super(struct file_system_type *type, int flags)
 {
        struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);
        static const struct super_operations default_op;
@@ -136,6 +137,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
 #else
                INIT_LIST_HEAD(&s->s_files);
 #endif
+               s->s_flags = flags;
                s->s_bdi = &default_backing_dev_info;
                INIT_HLIST_NODE(&s->s_instances);
                INIT_HLIST_BL_HEAD(&s->s_anon);
@@ -415,11 +417,13 @@ EXPORT_SYMBOL(generic_shutdown_super);
  *     @type:  filesystem type superblock should belong to
  *     @test:  comparison callback
  *     @set:   setup callback
+ *     @flags: mount flags
  *     @data:  argument to each of them
  */
 struct super_block *sget(struct file_system_type *type,
                        int (*test)(struct super_block *,void *),
                        int (*set)(struct super_block *,void *),
+                       int flags,
                        void *data)
 {
        struct super_block *s = NULL;
@@ -450,7 +454,7 @@ retry:
        }
        if (!s) {
                spin_unlock(&sb_lock);
-               s = alloc_super(type);
+               s = alloc_super(type, flags);
                if (!s)
                        return ERR_PTR(-ENOMEM);
                goto retry;
@@ -925,13 +929,12 @@ struct dentry *mount_ns(struct file_system_type *fs_type, int flags,
 {
        struct super_block *sb;
 
-       sb = sget(fs_type, ns_test_super, ns_set_super, data);
+       sb = sget(fs_type, ns_test_super, ns_set_super, flags, data);
        if (IS_ERR(sb))
                return ERR_CAST(sb);
 
        if (!sb->s_root) {
                int err;
-               sb->s_flags = flags;
                err = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
                if (err) {
                        deactivate_locked_super(sb);
@@ -992,7 +995,8 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
                error = -EBUSY;
                goto error_bdev;
        }
-       s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
+       s = sget(fs_type, test_bdev_super, set_bdev_super, flags | MS_NOSEC,
+                bdev);
        mutex_unlock(&bdev->bd_fsfreeze_mutex);
        if (IS_ERR(s))
                goto error_s;
@@ -1017,7 +1021,6 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
        } else {
                char b[BDEVNAME_SIZE];
 
-               s->s_flags = flags | MS_NOSEC;
                s->s_mode = mode;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                sb_set_blocksize(s, block_size(bdev));
@@ -1062,13 +1065,11 @@ struct dentry *mount_nodev(struct file_system_type *fs_type,
        int (*fill_super)(struct super_block *, void *, int))
 {
        int error;
-       struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
+       struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL);
 
        if (IS_ERR(s))
                return ERR_CAST(s);
 
-       s->s_flags = flags;
-
        error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
        if (error) {
                deactivate_locked_super(s);
@@ -1091,11 +1092,10 @@ struct dentry *mount_single(struct file_system_type *fs_type,
        struct super_block *s;
        int error;
 
-       s = sget(fs_type, compare_single, set_anon_super, NULL);
+       s = sget(fs_type, compare_single, set_anon_super, flags, NULL);
        if (IS_ERR(s))
                return ERR_CAST(s);
        if (!s->s_root) {
-               s->s_flags = flags;
                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
                if (error) {
                        deactivate_locked_super(s);
index 11e3d1c449018dcf9a95c352746f46d6522c4cb2..eb8722dc556f5b567c40438919c6ef1ddeef084d 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
  */
 static int __sync_filesystem(struct super_block *sb, int wait)
 {
-       /*
-        * This should be safe, as we require bdi backing to actually
-        * write out data in the first place
-        */
-       if (sb->s_bdi == &noop_backing_dev_info)
-               return 0;
-
-       if (sb->s_qcop && sb->s_qcop->quota_sync)
-               sb->s_qcop->quota_sync(sb, -1, wait);
-
        if (wait)
                sync_inodes_sb(sb);
        else
@@ -77,29 +67,48 @@ int sync_filesystem(struct super_block *sb)
 }
 EXPORT_SYMBOL_GPL(sync_filesystem);
 
-static void sync_one_sb(struct super_block *sb, void *arg)
+static void sync_inodes_one_sb(struct super_block *sb, void *arg)
 {
        if (!(sb->s_flags & MS_RDONLY))
-               __sync_filesystem(sb, *(int *)arg);
+               sync_inodes_sb(sb);
 }
-/*
- * Sync all the data for all the filesystems (called by sys_sync() and
- * emergency sync)
- */
-static void sync_filesystems(int wait)
+
+static void sync_fs_one_sb(struct super_block *sb, void *arg)
 {
-       iterate_supers(sync_one_sb, &wait);
+       if (!(sb->s_flags & MS_RDONLY) && sb->s_op->sync_fs)
+               sb->s_op->sync_fs(sb, *(int *)arg);
+}
+
+static void fdatawrite_one_bdev(struct block_device *bdev, void *arg)
+{
+       filemap_fdatawrite(bdev->bd_inode->i_mapping);
+}
+
+static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
+{
+       filemap_fdatawait(bdev->bd_inode->i_mapping);
 }
 
 /*
- * sync everything.  Start out by waking pdflush, because that writes back
- * all queues in parallel.
+ * Sync everything. We start by waking flusher threads so that most of
+ * writeback runs on all devices in parallel. Then we sync all inodes reliably
+ * which effectively also waits for all flusher threads to finish doing
+ * writeback. At this point all data is on disk so metadata should be stable
+ * and we tell filesystems to sync their metadata via ->sync_fs() calls.
+ * Finally, we writeout all block devices because some filesystems (e.g. ext2)
+ * just write metadata (such as inodes or bitmaps) to block device page cache
+ * and do not sync it on their own in ->sync_fs().
  */
 SYSCALL_DEFINE0(sync)
 {
+       int nowait = 0, wait = 1;
+
        wakeup_flusher_threads(0, WB_REASON_SYNC);
-       sync_filesystems(0);
-       sync_filesystems(1);
+       iterate_supers(sync_inodes_one_sb, NULL);
+       iterate_supers(sync_fs_one_sb, &nowait);
+       iterate_supers(sync_fs_one_sb, &wait);
+       iterate_bdevs(fdatawrite_one_bdev, NULL);
+       iterate_bdevs(fdatawait_one_bdev, NULL);
        if (unlikely(laptop_mode))
                laptop_sync_completion();
        return 0;
@@ -107,12 +116,18 @@ SYSCALL_DEFINE0(sync)
 
 static void do_sync_work(struct work_struct *work)
 {
+       int nowait = 0;
+
        /*
         * Sync twice to reduce the possibility we skipped some inodes / pages
         * because they were temporarily locked
         */
-       sync_filesystems(0);
-       sync_filesystems(0);
+       iterate_supers(sync_inodes_one_sb, &nowait);
+       iterate_supers(sync_fs_one_sb, &nowait);
+       iterate_bdevs(fdatawrite_one_bdev, NULL);
+       iterate_supers(sync_inodes_one_sb, &nowait);
+       iterate_supers(sync_fs_one_sb, &nowait);
+       iterate_bdevs(fdatawrite_one_bdev, NULL);
        printk("Emergency Sync complete\n");
        kfree(work);
 }
index e6bb9b2a4cbef3df52450d349a87a316844d6c8a..a5cf784f9cc2abec93c2a5272345838e20fb62ad 100644 (file)
@@ -300,15 +300,15 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
 static int sysfs_dentry_delete(const struct dentry *dentry)
 {
        struct sysfs_dirent *sd = dentry->d_fsdata;
-       return !!(sd->s_flags & SYSFS_FLAG_REMOVED);
+       return !(sd && !(sd->s_flags & SYSFS_FLAG_REMOVED));
 }
 
-static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct sysfs_dirent *sd;
        int is_dir;
 
-       if (nd->flags & LOOKUP_RCU)
+       if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        sd = dentry->d_fsdata;
@@ -355,18 +355,15 @@ out_bad:
        return 0;
 }
 
-static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode)
+static void sysfs_dentry_release(struct dentry *dentry)
 {
-       struct sysfs_dirent * sd = dentry->d_fsdata;
-
-       sysfs_put(sd);
-       iput(inode);
+       sysfs_put(dentry->d_fsdata);
 }
 
-static const struct dentry_operations sysfs_dentry_ops = {
+const struct dentry_operations sysfs_dentry_ops = {
        .d_revalidate   = sysfs_dentry_revalidate,
        .d_delete       = sysfs_dentry_delete,
-       .d_iput         = sysfs_dentry_iput,
+       .d_release      = sysfs_dentry_release,
 };
 
 struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
@@ -764,7 +761,7 @@ int sysfs_create_dir(struct kobject * kobj)
 }
 
 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
-                               struct nameidata *nd)
+                               unsigned int flags)
 {
        struct dentry *ret = NULL;
        struct dentry *parent = dentry->d_parent;
@@ -786,6 +783,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
                ret = ERR_PTR(-ENOENT);
                goto out_unlock;
        }
+       dentry->d_fsdata = sysfs_get(sd);
 
        /* attach dentry and inode */
        inode = sysfs_get_inode(dir->i_sb, sd);
@@ -795,16 +793,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
        }
 
        /* instantiate and hash dentry */
-       ret = d_find_alias(inode);
-       if (!ret) {
-               d_set_d_op(dentry, &sysfs_dentry_ops);
-               dentry->d_fsdata = sysfs_get(sd);
-               d_add(dentry, inode);
-       } else {
-               d_move(ret, dentry);
-               iput(inode);
-       }
-
+       ret = d_materialise_unique(dentry, inode);
  out_unlock:
        mutex_unlock(&sysfs_mutex);
        return ret;
index 52c3bdb66a849b98df33cefccff5b6cc0a7ded8c..71eb7e2539274a5cacd1fe61ba0bca46db8381b4 100644 (file)
@@ -68,6 +68,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
        }
        root->d_fsdata = &sysfs_root;
        sb->s_root = root;
+       sb->s_d_op = &sysfs_dentry_ops;
        return 0;
 }
 
@@ -117,13 +118,12 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
        for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
                info->ns[type] = kobj_ns_grab_current(type);
 
-       sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);
+       sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);
        if (IS_ERR(sb) || sb->s_fs_info != info)
                free_sysfs_super_info(info);
        if (IS_ERR(sb))
                return ERR_CAST(sb);
        if (!sb->s_root) {
-               sb->s_flags = flags;
                error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
                if (error) {
                        deactivate_locked_super(sb);
index 661a9639570b973dcce69ac3abc4bdbe84cb6991..d73c0932bbd6f688b811784236fc1a78ffce3c37 100644 (file)
@@ -157,6 +157,7 @@ extern struct kmem_cache *sysfs_dir_cachep;
  */
 extern struct mutex sysfs_mutex;
 extern spinlock_t sysfs_assoc_lock;
+extern const struct dentry_operations sysfs_dentry_ops;
 
 extern const struct file_operations sysfs_dir_operations;
 extern const struct inode_operations sysfs_dir_inode_operations;
index 08d0b2568cd35e060a9e6b8ffda87d7d6569cbdb..80e1e2b18df17f3537050cd7557955a1c1cd6b49 100644 (file)
@@ -43,7 +43,6 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
         * then attach current time stamp.
         * But if the filesystem was marked clean, keep it clean.
         */
-       sb->s_dirt = 0;
        old_time = fs32_to_cpu(sbi, *sbi->s_sb_time);
        if (sbi->s_type == FSTYPE_SYSV4) {
                if (*sbi->s_sb_state == cpu_to_fs32(sbi, 0x7c269d38 - old_time))
@@ -57,23 +56,12 @@ static int sysv_sync_fs(struct super_block *sb, int wait)
        return 0;
 }
 
-static void sysv_write_super(struct super_block *sb)
-{
-       if (!(sb->s_flags & MS_RDONLY))
-               sysv_sync_fs(sb, 1);
-       else
-               sb->s_dirt = 0;
-}
-
 static int sysv_remount(struct super_block *sb, int *flags, char *data)
 {
        struct sysv_sb_info *sbi = SYSV_SB(sb);
-       lock_super(sb);
+
        if (sbi->s_forced_ro)
                *flags |= MS_RDONLY;
-       if (*flags & MS_RDONLY)
-               sysv_write_super(sb);
-       unlock_super(sb);
        return 0;
 }
 
@@ -81,9 +69,6 @@ static void sysv_put_super(struct super_block *sb)
 {
        struct sysv_sb_info *sbi = SYSV_SB(sb);
 
-       if (sb->s_dirt)
-               sysv_write_super(sb);
-
        if (!(sb->s_flags & MS_RDONLY)) {
                /* XXX ext2 also updates the state here */
                mark_buffer_dirty(sbi->s_bh1);
@@ -357,7 +342,6 @@ const struct super_operations sysv_sops = {
        .write_inode    = sysv_write_inode,
        .evict_inode    = sysv_evict_inode,
        .put_super      = sysv_put_super,
-       .write_super    = sysv_write_super,
        .sync_fs        = sysv_sync_fs,
        .remount_fs     = sysv_remount,
        .statfs         = sysv_statfs,
index d7466e2936148103f20c5a6dbec5fba33e4fb2f3..1c0d5f264767df5ebc7bf0dc77a0267b097a4052 100644 (file)
@@ -43,7 +43,7 @@ const struct dentry_operations sysv_dentry_operations = {
        .d_hash         = sysv_hash,
 };
 
-static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags)
 {
        struct inode * inode = NULL;
        ino_t ino;
@@ -80,7 +80,7 @@ static int sysv_mknod(struct inode * dir, struct dentry * dentry, umode_t mode,
        return err;
 }
 
-static int sysv_create(struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd)
+static int sysv_create(struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
 {
        return sysv_mknod(dir, dentry, mode, 0);
 }
index 11b07672f6c5586752b0448810226fdee81b049c..0bc35fdc58e2981fc455fc043c43f00deb10a0d8 100644 (file)
@@ -117,7 +117,6 @@ static inline void dirty_sb(struct super_block *sb)
        mark_buffer_dirty(sbi->s_bh1);
        if (sbi->s_bh1 != sbi->s_bh2)
                mark_buffer_dirty(sbi->s_bh2);
-       sb->s_dirt = 1;
 }
 
 
index 92df3b08153901350a433f8b95c95cd493479aad..bb3167257aabfed6d16452eed551e577c95b706d 100644 (file)
@@ -2802,6 +2802,8 @@ static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
                val = d->chk_fs;
        else if (dent == d->dfs_tst_rcvry)
                val = d->tst_rcvry;
+       else if (dent == d->dfs_ro_error)
+               val = c->ro_error;
        else
                return -EINVAL;
 
@@ -2885,6 +2887,8 @@ static ssize_t dfs_file_write(struct file *file, const char __user *u,
                d->chk_fs = val;
        else if (dent == d->dfs_tst_rcvry)
                d->tst_rcvry = val;
+       else if (dent == d->dfs_ro_error)
+               c->ro_error = !!val;
        else
                return -EINVAL;
 
@@ -2996,6 +3000,13 @@ int dbg_debugfs_init_fs(struct ubifs_info *c)
                goto out_remove;
        d->dfs_tst_rcvry = dent;
 
+       fname = "ro_error";
+       dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
+                                  &dfs_fops);
+       if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_ro_error = dent;
+
        return 0;
 
 out_remove:
index 486a8e024fb65b15f1a20173877c5b1e361c7bae..8b8cc4e945f4014bd8e0a77d1d9bde0197f0fa76 100644 (file)
@@ -79,6 +79,10 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
  * @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
  * @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
  * @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
+ * @dfs_ro_error: debugfs knob to switch UBIFS to R/O mode (different to
+ *                re-mounting to R/O mode because it does not flush any buffers
+ *                and UBIFS just starts returning -EROFS on all write
+ *               operations)
  */
 struct ubifs_debug_info {
        struct ubifs_zbranch old_zroot;
@@ -122,6 +126,7 @@ struct ubifs_debug_info {
        struct dentry *dfs_chk_lprops;
        struct dentry *dfs_chk_fs;
        struct dentry *dfs_tst_rcvry;
+       struct dentry *dfs_ro_error;
 };
 
 /**
index a6d42efc76d227d62289f852982160442d7e5cea..c95681cf1b71cfe7c99f70d5d88eb2f54c7804c0 100644 (file)
@@ -184,7 +184,7 @@ static int dbg_check_name(const struct ubifs_info *c,
 }
 
 static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
-                                  struct nameidata *nd)
+                                  unsigned int flags)
 {
        int err;
        union ubifs_key key;
@@ -246,7 +246,7 @@ out:
 }
 
 static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                       struct nameidata *nd)
+                       bool excl)
 {
        struct inode *inode;
        struct ubifs_info *c = dir->i_sb->s_fs_info;
@@ -969,7 +969,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
                        .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
        struct timespec time;
-       unsigned int saved_nlink;
+       unsigned int uninitialized_var(saved_nlink);
 
        /*
         * Budget request settings: deletion direntry, new direntry, removing
index b02734db187c2d1b2b79696c6a133482376c860b..cebf17ea045824a052e024a0e0e954c0b5a0c9e9 100644 (file)
@@ -176,7 +176,7 @@ int ubifs_orphan_start_commit(struct ubifs_info *c)
                *last = orphan;
                last = &orphan->cnext;
        }
-       *last = orphan->cnext;
+       *last = NULL;
        c->cmt_orphans = c->new_orphans;
        c->new_orphans = 0;
        dbg_cmt("%d orphans to commit", c->cmt_orphans);
@@ -382,7 +382,7 @@ static int consolidate(struct ubifs_info *c)
                        last = &orphan->cnext;
                        cnt += 1;
                }
-               *last = orphan->cnext;
+               *last = NULL;
                ubifs_assert(cnt == c->tot_orphans - c->new_orphans);
                c->cmt_orphans = cnt;
                c->ohead_lnum = c->orph_first;
index 3a2da7e476e5c8e7b346a8c3aaca9a1454659ca8..eba46d4a76192c017846c4389addf2ebdcc2a78e 100644 (file)
@@ -1007,7 +1007,7 @@ out:
  */
 int ubifs_replay_journal(struct ubifs_info *c)
 {
-       int err, i, lnum, offs, free;
+       int err, lnum, free;
 
        BUILD_BUG_ON(UBIFS_TRUN_KEY > 5);
 
@@ -1025,25 +1025,17 @@ int ubifs_replay_journal(struct ubifs_info *c)
        dbg_mnt("start replaying the journal");
        c->replaying = 1;
        lnum = c->ltail_lnum = c->lhead_lnum;
-       offs = c->lhead_offs;
 
-       for (i = 0; i < c->log_lebs; i++, lnum++) {
-               if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) {
-                       /*
-                        * The log is logically circular, we reached the last
-                        * LEB, switch to the first one.
-                        */
-                       lnum = UBIFS_LOG_LNUM;
-                       offs = 0;
-               }
-               err = replay_log_leb(c, lnum, offs, c->sbuf);
+       lnum = UBIFS_LOG_LNUM;
+       do {
+               err = replay_log_leb(c, lnum, 0, c->sbuf);
                if (err == 1)
                        /* We hit the end of the log */
                        break;
                if (err)
                        goto out;
-               offs = 0;
-       }
+               lnum = ubifs_next_log_lnum(c, lnum);
+       } while (lnum != UBIFS_LOG_LNUM);
 
        err = replay_buds(c);
        if (err)
index ef3d1ba6d992b8ffb9ab0d57e633a22d586758d2..15e2fc5aa60bd4790a86c828aaea6995b17e1737 100644 (file)
@@ -718,8 +718,12 @@ static int fixup_free_space(struct ubifs_info *c)
                lnum = ubifs_next_log_lnum(c, lnum);
        }
 
-       /* Fixup the current log head */
-       err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
+       /*
+        * Fixup the log head which contains the only a CS node at the
+        * beginning.
+        */
+       err = fixup_leb(c, c->lhead_lnum,
+                       ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size));
        if (err)
                goto out;
 
index 5862dd9d278402fe140ad9096fd8eacb7c1f1909..1c766c39c03819b4d088f19f0215c63a89f2b539 100644 (file)
@@ -2136,7 +2136,7 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
 
        dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
 
-       sb = sget(fs_type, sb_test, sb_set, c);
+       sb = sget(fs_type, sb_test, sb_set, flags, c);
        if (IS_ERR(sb)) {
                err = PTR_ERR(sb);
                kfree(c);
@@ -2153,7 +2153,6 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
                        goto out_deact;
                }
        } else {
-               sb->s_flags = flags;
                err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
                if (err)
                        goto out_deact;
index 18024178ac4c040a3f23181ff2dc1a5cc48f2dc8..544b2799a9114c4620844bec32b9921881da97b9 100644 (file)
@@ -251,7 +251,7 @@ out_ok:
 }
 
 static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
-                                struct nameidata *nd)
+                                unsigned int flags)
 {
        struct inode *inode = NULL;
        struct fileIdentDesc cfi;
@@ -551,7 +551,7 @@ static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
 }
 
 static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                     struct nameidata *nd)
+                     bool excl)
 {
        struct udf_fileident_bh fibh;
        struct inode *inode;
index 42694e11c23de46b25f1177888b97ec2aac1cf32..1b3e410bf334b206eea15615d52b1ab16656de88 100644 (file)
@@ -116,7 +116,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
        ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS)
                ubh_sync_block(UCPI_UBH(ucpi));
-       sb->s_dirt = 1;
+       ufs_mark_sb_dirty(sb);
        
        unlock_super (sb);
        UFSD("EXIT\n");
@@ -214,7 +214,7 @@ do_more:
                goto do_more;
        }
 
-       sb->s_dirt = 1;
+       ufs_mark_sb_dirty(sb);
        unlock_super (sb);
        UFSD("EXIT\n");
        return;
@@ -557,7 +557,7 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
        ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS)
                ubh_sync_block(UCPI_UBH(ucpi));
-       sb->s_dirt = 1;
+       ufs_mark_sb_dirty(sb);
 
        UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment);
        
@@ -677,7 +677,7 @@ succed:
        ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS)
                ubh_sync_block(UCPI_UBH(ucpi));
-       sb->s_dirt = 1;
+       ufs_mark_sb_dirty(sb);
 
        result += cgno * uspi->s_fpg;
        UFSD("EXIT3, result %llu\n", (unsigned long long)result);
index 4ec5c1085a87ca56549491f52cec362e50a303d1..e84cbe21b9867d1f50ebe9d4c0fc3c7e1d05e7d0 100644 (file)
@@ -116,7 +116,7 @@ void ufs_free_inode (struct inode * inode)
        if (sb->s_flags & MS_SYNCHRONOUS)
                ubh_sync_block(UCPI_UBH(ucpi));
        
-       sb->s_dirt = 1;
+       ufs_mark_sb_dirty(sb);
        unlock_super (sb);
        UFSD("EXIT\n");
 }
@@ -288,7 +288,7 @@ cg_found:
        ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
        if (sb->s_flags & MS_SYNCHRONOUS)
                ubh_sync_block(UCPI_UBH(ucpi));
-       sb->s_dirt = 1;
+       ufs_mark_sb_dirty(sb);
 
        inode->i_ino = cg * uspi->s_ipg + bit;
        inode_init_owner(inode, dir, mode);
index a2281cadefa120c444d3022843d7504019037c04..90d74b8f8eba8dacd536c74ac161cceddc241196 100644 (file)
@@ -46,7 +46,7 @@ static inline int ufs_add_nondir(struct dentry *dentry, struct inode *inode)
        return err;
 }
 
-static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
 {
        struct inode * inode = NULL;
        ino_t ino;
@@ -71,7 +71,7 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
  * with d_instantiate(). 
  */
 static int ufs_create (struct inode * dir, struct dentry * dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        struct inode *inode;
        int err;
index 302f340d0071280adaef9366b98280b18e5dd32a..444927e5706b773380d9050213a8179b3d611fd9 100644 (file)
@@ -302,7 +302,7 @@ void ufs_error (struct super_block * sb, const char * function,
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
                ubh_mark_buffer_dirty(USPI_UBH(uspi));
-               sb->s_dirt = 1;
+               ufs_mark_sb_dirty(sb);
                sb->s_flags |= MS_RDONLY;
        }
        va_start (args, fmt);
@@ -334,7 +334,7 @@ void ufs_panic (struct super_block * sb, const char * function,
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
                ubh_mark_buffer_dirty(USPI_UBH(uspi));
-               sb->s_dirt = 1;
+               ufs_mark_sb_dirty(sb);
        }
        va_start (args, fmt);
        vsnprintf (error_buf, sizeof(error_buf), fmt, args);
@@ -691,6 +691,83 @@ static void ufs_put_super_internal(struct super_block *sb)
        UFSD("EXIT\n");
 }
 
+static int ufs_sync_fs(struct super_block *sb, int wait)
+{
+       struct ufs_sb_private_info * uspi;
+       struct ufs_super_block_first * usb1;
+       struct ufs_super_block_third * usb3;
+       unsigned flags;
+
+       lock_ufs(sb);
+       lock_super(sb);
+
+       UFSD("ENTER\n");
+
+       flags = UFS_SB(sb)->s_flags;
+       uspi = UFS_SB(sb)->s_uspi;
+       usb1 = ubh_get_usb_first(uspi);
+       usb3 = ubh_get_usb_third(uspi);
+
+       usb1->fs_time = cpu_to_fs32(sb, get_seconds());
+       if ((flags & UFS_ST_MASK) == UFS_ST_SUN  ||
+           (flags & UFS_ST_MASK) == UFS_ST_SUNOS ||
+           (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
+               ufs_set_fs_state(sb, usb1, usb3,
+                               UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
+       ufs_put_cstotal(sb);
+
+       UFSD("EXIT\n");
+       unlock_super(sb);
+       unlock_ufs(sb);
+
+       return 0;
+}
+
+static void delayed_sync_fs(struct work_struct *work)
+{
+       struct ufs_sb_info *sbi;
+
+       sbi = container_of(work, struct ufs_sb_info, sync_work.work);
+
+       spin_lock(&sbi->work_lock);
+       sbi->work_queued = 0;
+       spin_unlock(&sbi->work_lock);
+
+       ufs_sync_fs(sbi->sb, 1);
+}
+
+void ufs_mark_sb_dirty(struct super_block *sb)
+{
+       struct ufs_sb_info *sbi = UFS_SB(sb);
+       unsigned long delay;
+
+       spin_lock(&sbi->work_lock);
+       if (!sbi->work_queued) {
+               delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+               queue_delayed_work(system_long_wq, &sbi->sync_work, delay);
+               sbi->work_queued = 1;
+       }
+       spin_unlock(&sbi->work_lock);
+}
+
+static void ufs_put_super(struct super_block *sb)
+{
+       struct ufs_sb_info * sbi = UFS_SB(sb);
+
+       UFSD("ENTER\n");
+
+       if (!(sb->s_flags & MS_RDONLY))
+               ufs_put_super_internal(sb);
+       cancel_delayed_work_sync(&sbi->sync_work);
+
+       ubh_brelse_uspi (sbi->s_uspi);
+       kfree (sbi->s_uspi);
+       kfree (sbi);
+       sb->s_fs_info = NULL;
+       UFSD("EXIT\n");
+       return;
+}
+
 static int ufs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct ufs_sb_info * sbi;
@@ -716,6 +793,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        if (!sbi)
                goto failed_nomem;
        sb->s_fs_info = sbi;
+       sbi->sb = sb;
 
        UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY));
        
@@ -727,6 +805,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        }
 #endif
        mutex_init(&sbi->mutex);
+       spin_lock_init(&sbi->work_lock);
+       INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);
        /*
         * Set default mount options
         * Parse mount options
@@ -1191,68 +1271,6 @@ failed_nomem:
        return -ENOMEM;
 }
 
-static int ufs_sync_fs(struct super_block *sb, int wait)
-{
-       struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
-       struct ufs_super_block_third * usb3;
-       unsigned flags;
-
-       lock_ufs(sb);
-       lock_super(sb);
-
-       UFSD("ENTER\n");
-
-       flags = UFS_SB(sb)->s_flags;
-       uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(uspi);
-       usb3 = ubh_get_usb_third(uspi);
-
-       usb1->fs_time = cpu_to_fs32(sb, get_seconds());
-       if ((flags & UFS_ST_MASK) == UFS_ST_SUN  ||
-           (flags & UFS_ST_MASK) == UFS_ST_SUNOS ||
-           (flags & UFS_ST_MASK) == UFS_ST_SUNx86)
-               ufs_set_fs_state(sb, usb1, usb3,
-                               UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
-       ufs_put_cstotal(sb);
-       sb->s_dirt = 0;
-
-       UFSD("EXIT\n");
-       unlock_super(sb);
-       unlock_ufs(sb);
-
-       return 0;
-}
-
-static void ufs_write_super(struct super_block *sb)
-{
-       if (!(sb->s_flags & MS_RDONLY))
-               ufs_sync_fs(sb, 1);
-       else
-               sb->s_dirt = 0;
-}
-
-static void ufs_put_super(struct super_block *sb)
-{
-       struct ufs_sb_info * sbi = UFS_SB(sb);
-               
-       UFSD("ENTER\n");
-
-       if (sb->s_dirt)
-               ufs_write_super(sb);
-
-       if (!(sb->s_flags & MS_RDONLY))
-               ufs_put_super_internal(sb);
-       
-       ubh_brelse_uspi (sbi->s_uspi);
-       kfree (sbi->s_uspi);
-       kfree (sbi);
-       sb->s_fs_info = NULL;
-       UFSD("EXIT\n");
-       return;
-}
-
-
 static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
 {
        struct ufs_sb_private_info * uspi;
@@ -1308,7 +1326,6 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
                        ufs_set_fs_state(sb, usb1, usb3,
                                UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time));
                ubh_mark_buffer_dirty (USPI_UBH(uspi));
-               sb->s_dirt = 0;
                sb->s_flags |= MS_RDONLY;
        } else {
        /*
@@ -1458,7 +1475,6 @@ static const struct super_operations ufs_super_ops = {
        .write_inode    = ufs_write_inode,
        .evict_inode    = ufs_evict_inode,
        .put_super      = ufs_put_super,
-       .write_super    = ufs_write_super,
        .sync_fs        = ufs_sync_fs,
        .statfs         = ufs_statfs,
        .remount_fs     = ufs_remount,
index 528750b7e701ab781018a7af83c83fff8de79277..343e6fc571e5b3976b6132d43dccb03b538d9380 100644 (file)
@@ -20,6 +20,10 @@ struct ufs_sb_info {
        unsigned s_mount_opt;
        struct mutex mutex;
        struct task_struct *mutex_owner;
+       struct super_block *sb;
+       int work_queued; /* non-zero if the delayed work is queued */
+       struct delayed_work sync_work; /* FS sync delayed work */
+       spinlock_t work_lock; /* protects sync_work and work_queued */
 };
 
 struct ufs_inode_info {
@@ -123,6 +127,7 @@ extern __printf(3, 4)
 void ufs_error(struct super_block *, const char *, const char *, ...);
 extern __printf(3, 4)
 void ufs_panic(struct super_block *, const char *, const char *, ...);
+void ufs_mark_sb_dirty(struct super_block *sb);
 
 /* symlink.c */
 extern const struct inode_operations ufs_fast_symlink_inode_operations;
index 8aba544f9fad80b2a79ca581d6360340cf5e2314..0cbd5d340b6705b9c6e22ff0a60a49891c302860 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/stat.h>
 #include <linux/fs.h>
+#include <linux/workqueue.h>
 
 #include <asm/div64.h>
 typedef __u64 __bitwise __fs64;
index 9d1aeb7e273492f67e97c3f43108a57000cd7c0f..4f33c32affe3d2eb4bec9c5ca8d71a33bbc5032a 100644 (file)
@@ -1074,13 +1074,13 @@ restart:
         * If we couldn't get anything, give up.
         */
        if (bno_cur_lt == NULL && bno_cur_gt == NULL) {
+               xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
+
                if (!forced++) {
                        trace_xfs_alloc_near_busy(args);
                        xfs_log_force(args->mp, XFS_LOG_SYNC);
                        goto restart;
                }
-
-               xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
                trace_xfs_alloc_size_neither(args);
                args->agbno = NULLAGBLOCK;
                return 0;
@@ -2434,13 +2434,22 @@ xfs_alloc_vextent_worker(
        current_restore_flags_nested(&pflags, PF_FSTRANS);
 }
 
-
-int                            /* error */
+/*
+ * Data allocation requests often come in with little stack to work on. Push
+ * them off to a worker thread so there is lots of stack to use. Metadata
+ * requests, OTOH, are generally from low stack usage paths, so avoid the
+ * context switch overhead here.
+ */
+int
 xfs_alloc_vextent(
-       xfs_alloc_arg_t *args)  /* allocation argument structure */
+       struct xfs_alloc_arg    *args)
 {
        DECLARE_COMPLETION_ONSTACK(done);
 
+       if (!args->userdata)
+               return __xfs_alloc_vextent(args);
+
+
        args->done = &done;
        INIT_WORK_ONSTACK(&args->work, xfs_alloc_vextent_worker);
        queue_work(xfs_alloc_wq, &args->work);
index a4beb421018a03aa84d0cb807d4a71b1db8f927b..269b35c084dab6906267ccf66f473c98e85ce473 100644 (file)
@@ -989,27 +989,6 @@ xfs_buf_ioerror_alert(
                (__uint64_t)XFS_BUF_ADDR(bp), func, bp->b_error, bp->b_length);
 }
 
-int
-xfs_bwrite(
-       struct xfs_buf          *bp)
-{
-       int                     error;
-
-       ASSERT(xfs_buf_islocked(bp));
-
-       bp->b_flags |= XBF_WRITE;
-       bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q);
-
-       xfs_bdstrat_cb(bp);
-
-       error = xfs_buf_iowait(bp);
-       if (error) {
-               xfs_force_shutdown(bp->b_target->bt_mount,
-                                  SHUTDOWN_META_IO_ERROR);
-       }
-       return error;
-}
-
 /*
  * Called when we want to stop a buffer from getting written or read.
  * We attach the EIO error, muck with its flags, and call xfs_buf_ioend
@@ -1079,14 +1058,7 @@ xfs_bioerror_relse(
        return EIO;
 }
 
-
-/*
- * All xfs metadata buffers except log state machine buffers
- * get this attached as their b_bdstrat callback function.
- * This is so that we can catch a buffer
- * after prematurely unpinning it to forcibly shutdown the filesystem.
- */
-int
+STATIC int
 xfs_bdstrat_cb(
        struct xfs_buf  *bp)
 {
@@ -1107,6 +1079,27 @@ xfs_bdstrat_cb(
        return 0;
 }
 
+int
+xfs_bwrite(
+       struct xfs_buf          *bp)
+{
+       int                     error;
+
+       ASSERT(xfs_buf_islocked(bp));
+
+       bp->b_flags |= XBF_WRITE;
+       bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q);
+
+       xfs_bdstrat_cb(bp);
+
+       error = xfs_buf_iowait(bp);
+       if (error) {
+               xfs_force_shutdown(bp->b_target->bt_mount,
+                                  SHUTDOWN_META_IO_ERROR);
+       }
+       return error;
+}
+
 /*
  * Wrapper around bdstrat so that we can stop data from going to disk in case
  * we are shutting down the filesystem.  Typically user data goes thru this
@@ -1243,7 +1236,7 @@ xfs_buf_iorequest(
         */
        atomic_set(&bp->b_io_remaining, 1);
        _xfs_buf_ioapply(bp);
-       _xfs_buf_ioend(bp, 0);
+       _xfs_buf_ioend(bp, 1);
 
        xfs_buf_rele(bp);
 }
index 7f1d1392ce37c292a04e8a22268537527687e10f..79344c48008eedaab4aaa21dc6ed28fe328607d3 100644 (file)
@@ -180,7 +180,6 @@ extern void xfs_buf_unlock(xfs_buf_t *);
 extern int xfs_bwrite(struct xfs_buf *bp);
 
 extern void xfsbdstrat(struct xfs_mount *, struct xfs_buf *);
-extern int xfs_bdstrat_cb(struct xfs_buf *);
 
 extern void xfs_buf_ioend(xfs_buf_t *, int);
 extern void xfs_buf_ioerror(xfs_buf_t *, int);
index 45df2b857d482fe478c3f4965ddfa57a648eb6ee..d9e451115f980ac1529c4e89aa89665c82661360 100644 (file)
@@ -954,7 +954,7 @@ xfs_buf_iodone_callbacks(
 
                if (!XFS_BUF_ISSTALE(bp)) {
                        bp->b_flags |= XBF_WRITE | XBF_ASYNC | XBF_DONE;
-                       xfs_bdstrat_cb(bp);
+                       xfs_buf_iorequest(bp);
                } else {
                        xfs_buf_relse(bp);
                }
index 3a05a41b5d76b8bfbbc6399d287f78b56e06ccc4..1f1535d25a9bb726b96742fa82c59dec74183f51 100644 (file)
@@ -208,6 +208,7 @@ xfs_open_by_handle(
        struct inode            *inode;
        struct dentry           *dentry;
        fmode_t                 fmode;
+       struct path             path;
 
        if (!capable(CAP_SYS_ADMIN))
                return -XFS_ERROR(EPERM);
@@ -252,8 +253,10 @@ xfs_open_by_handle(
                goto out_dput;
        }
 
-       filp = dentry_open(dentry, mntget(parfilp->f_path.mnt),
-                          hreq->oflags, cred);
+       path.mnt = parfilp->f_path.mnt;
+       path.dentry = dentry;
+       filp = dentry_open(&path, hreq->oflags, cred);
+       dput(dentry);
        if (IS_ERR(filp)) {
                put_unused_fd(fd);
                return PTR_ERR(filp);
index 1a25fd80279882bae3c0a11176ec61b35ac830db..9c4340f5c3e0ff92bb84505155c3ba4f9a4bac54 100644 (file)
@@ -179,7 +179,7 @@ xfs_vn_create(
        struct inode    *dir,
        struct dentry   *dentry,
        umode_t         mode,
-       struct nameidata *nd)
+       bool            flags)
 {
        return xfs_vn_mknod(dir, dentry, mode, 0);
 }
@@ -197,7 +197,7 @@ STATIC struct dentry *
 xfs_vn_lookup(
        struct inode    *dir,
        struct dentry   *dentry,
-       struct nameidata *nd)
+       unsigned int flags)
 {
        struct xfs_inode *cip;
        struct xfs_name name;
@@ -222,7 +222,7 @@ STATIC struct dentry *
 xfs_vn_ci_lookup(
        struct inode    *dir,
        struct dentry   *dentry,
-       struct nameidata *nd)
+       unsigned int flags)
 {
        struct xfs_inode *ip;
        struct xfs_name xname;
index 9e6e1c6eb60a94885f1e9c08038cc8e081f86547..18fd41033e03a97be6f3e070082d1aca5323330f 100644 (file)
@@ -117,9 +117,6 @@ struct acpi_device;
 typedef int (*acpi_op_add) (struct acpi_device * device);
 typedef int (*acpi_op_remove) (struct acpi_device * device, int type);
 typedef int (*acpi_op_start) (struct acpi_device * device);
-typedef int (*acpi_op_suspend) (struct acpi_device * device,
-                               pm_message_t state);
-typedef int (*acpi_op_resume) (struct acpi_device * device);
 typedef int (*acpi_op_bind) (struct acpi_device * device);
 typedef int (*acpi_op_unbind) (struct acpi_device * device);
 typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
@@ -133,8 +130,6 @@ struct acpi_device_ops {
        acpi_op_add add;
        acpi_op_remove remove;
        acpi_op_start start;
-       acpi_op_suspend suspend;
-       acpi_op_resume resume;
        acpi_op_bind bind;
        acpi_op_unbind unbind;
        acpi_op_notify notify;
index 9d650476d5dcf8eb346c8520db639efbb9907964..64ec644808bcb82951f38eaa682cb536e605d7bf 100644 (file)
@@ -59,10 +59,7 @@ struct acpi_processor_cx {
        u8 entry_method;
        u8 index;
        u32 latency;
-       u32 latency_ticks;
        u32 power;
-       u32 usage;
-       u64 time;
        u8 bm_sts_skip;
        char desc[ACPI_CX_DESC_LEN];
 };
@@ -334,8 +331,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr);
 int acpi_processor_hotplug(struct acpi_processor *pr);
 int acpi_processor_power_exit(struct acpi_processor *pr,
                              struct acpi_device *device);
-int acpi_processor_suspend(struct acpi_device * device, pm_message_t state);
-int acpi_processor_resume(struct acpi_device * device);
+int acpi_processor_suspend(struct device *dev);
+int acpi_processor_resume(struct device *dev);
 extern struct cpuidle_driver acpi_idle_driver;
 
 /* in processor_thermal.c */
index c544356b374b62285b325c2df1ab77008c2422d1..294b1e755ab26e7bb47d9f1800ae132fc6667950 100644 (file)
@@ -18,7 +18,7 @@ static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
 {
        if (dev)
                dev->cma_area = cma;
-       if (!dev || !dma_contiguous_default_area)
+       if (!dev && !dma_contiguous_default_area)
                dma_contiguous_default_area = cma;
 }
 
index 2314ad8b3c9cced6a4679441d7c6b25afe500348..b1a520ec8b59dd0975bc4e738ce2398ca19dc363 100644 (file)
@@ -140,6 +140,7 @@ struct kiocb {
                (x)->ki_dtor = NULL;                    \
                (x)->ki_obj.tsk = tsk;                  \
                (x)->ki_user_data = 0;                  \
+               (x)->private = NULL;                    \
        } while (0)
 
 #define AIO_RING_MAGIC                 0xa10a10a1
index ba43f408baa38907a8f63a64314e07bb622a6e7f..07954b05b86cc3ac9c4f72aa97584b551914631e 100644 (file)
@@ -827,7 +827,6 @@ extern bool __blk_end_request_err(struct request *rq, int error);
 extern void blk_complete_request(struct request *);
 extern void __blk_complete_request(struct request *);
 extern void blk_abort_request(struct request *);
-extern void blk_abort_queue(struct request_queue *);
 extern void blk_unprep_request(struct request *);
 
 /*
index 324fe08ea3b140b7b8b92f7129ad334df2e260d5..6d6795d46a7509f01e4a12993e9c7de34b02d975 100644 (file)
@@ -91,6 +91,11 @@ extern void *__alloc_bootmem_node_nopanic(pg_data_t *pgdat,
                                  unsigned long size,
                                  unsigned long align,
                                  unsigned long goal);
+void *___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
+                                 unsigned long size,
+                                 unsigned long align,
+                                 unsigned long goal,
+                                 unsigned long limit);
 extern void *__alloc_bootmem_low(unsigned long size,
                                 unsigned long align,
                                 unsigned long goal);
index 68d56effc32860ac29a26487316fcf75b4642261..d10b7ed595b15c07c58f30e08ca841dafb2aa0a1 100644 (file)
@@ -360,11 +360,11 @@ struct cpu_vfs_cap_data {
 
 #define CAP_WAKE_ALARM            35
 
-/* Allow preventing system suspends while epoll events are pending */
+/* Allow preventing system suspends */
 
-#define CAP_EPOLLWAKEUP      36
+#define CAP_BLOCK_SUSPEND    36
 
-#define CAP_LAST_CAP         CAP_EPOLLWAKEUP
+#define CAP_LAST_CAP         CAP_BLOCK_SUSPEND
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
index 2521a95fa6d98597d1fafe4d4cff23ce9dc0f069..44c87e731e9d4c5fff13cbf851694cd41356fb04 100644 (file)
@@ -163,16 +163,8 @@ struct ceph_connection {
 
        /* connection negotiation temps */
        char in_banner[CEPH_BANNER_MAX_LEN];
-       union {
-               struct {  /* outgoing connection */
-                       struct ceph_msg_connect out_connect;
-                       struct ceph_msg_connect_reply in_reply;
-               };
-               struct {  /* incoming */
-                       struct ceph_msg_connect in_connect;
-                       struct ceph_msg_connect_reply out_reply;
-               };
-       };
+       struct ceph_msg_connect out_connect;
+       struct ceph_msg_connect_reply in_reply;
        struct ceph_entity_addr actual_peer_addr;
 
        /* message out temps */
index 6c26a3da0e03173b29ce1535c9833537f85a6786..89dcd30ac8ea81144fe5e44d00e0c473e01331f8 100644 (file)
@@ -34,6 +34,7 @@ struct cpuidle_driver;
 struct cpuidle_state_usage {
        void            *driver_data;
 
+       unsigned long long      disable;
        unsigned long long      usage;
        unsigned long long      time; /* in US */
 };
@@ -46,7 +47,7 @@ struct cpuidle_state {
        unsigned int    exit_latency; /* in US */
        int             power_usage; /* in mW */
        unsigned int    target_residency; /* in US */
-       unsigned int    disable;
+       bool            disabled; /* disabled on all CPUs */
 
        int (*enter)    (struct cpuidle_device *dev,
                        struct cpuidle_driver *drv,
@@ -136,13 +137,17 @@ struct cpuidle_driver {
 extern void disable_cpuidle(void);
 extern int cpuidle_idle_call(void);
 extern int cpuidle_register_driver(struct cpuidle_driver *drv);
-struct cpuidle_driver *cpuidle_get_driver(void);
+extern struct cpuidle_driver *cpuidle_get_driver(void);
+extern struct cpuidle_driver *cpuidle_driver_ref(void);
+extern void cpuidle_driver_unref(void);
 extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
 extern int cpuidle_register_device(struct cpuidle_device *dev);
 extern void cpuidle_unregister_device(struct cpuidle_device *dev);
 
 extern void cpuidle_pause_and_lock(void);
 extern void cpuidle_resume_and_unlock(void);
+extern void cpuidle_pause(void);
+extern void cpuidle_resume(void);
 extern int cpuidle_enable_device(struct cpuidle_device *dev);
 extern void cpuidle_disable_device(struct cpuidle_device *dev);
 extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
@@ -157,6 +162,8 @@ static inline int cpuidle_idle_call(void) { return -ENODEV; }
 static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
 {return -ENODEV; }
 static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
+static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; }
+static inline void cpuidle_driver_unref(void) {}
 static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
 static inline int cpuidle_register_device(struct cpuidle_device *dev)
 {return -ENODEV; }
@@ -164,6 +171,8 @@ static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
 
 static inline void cpuidle_pause_and_lock(void) { }
 static inline void cpuidle_resume_and_unlock(void) { }
+static inline void cpuidle_pause(void) { }
+static inline void cpuidle_resume(void) { }
 static inline int cpuidle_enable_device(struct cpuidle_device *dev)
 {return -ENODEV; }
 static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
@@ -202,14 +211,7 @@ struct cpuidle_governor {
 extern int cpuidle_register_governor(struct cpuidle_governor *gov);
 extern void cpuidle_unregister_governor(struct cpuidle_governor *gov);
 
-#ifdef CONFIG_INTEL_IDLE
-extern int intel_idle_cpu_init(int cpu);
 #else
-static inline int intel_idle_cpu_init(int cpu) { return -1; }
-#endif
-
-#else
-static inline int intel_idle_cpu_init(int cpu) { return -1; }
 
 static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
 {return 0;}
index 094789ff3e9f4e958ab35a90aa001d05997a0fa2..caa34e50537e895a7a4b5149148f03157e253129 100644 (file)
@@ -128,7 +128,7 @@ struct dentry {
                struct rcu_head d_rcu;
        } d_u;
        struct list_head d_subdirs;     /* our children */
-       struct list_head d_alias;       /* inode alias list */
+       struct hlist_node d_alias;      /* inode alias list */
 };
 
 /*
@@ -144,7 +144,7 @@ enum dentry_d_lock_class
 };
 
 struct dentry_operations {
-       int (*d_revalidate)(struct dentry *, struct nameidata *);
+       int (*d_revalidate)(struct dentry *, unsigned int);
        int (*d_hash)(const struct dentry *, const struct inode *,
                        struct qstr *);
        int (*d_compare)(const struct dentry *, const struct inode *,
index 161d96241b1b4da3b9a0909749709a33bcca33c5..6de94151ff6f7e8646ab16d7f093cea3c079f1fa 100644 (file)
@@ -865,8 +865,6 @@ extern int (*platform_notify_remove)(struct device *dev);
 extern struct device *get_device(struct device *dev);
 extern void put_device(struct device *dev);
 
-extern void wait_for_device_probe(void);
-
 #ifdef CONFIG_DEVTMPFS
 extern int devtmpfs_create_node(struct device *dev);
 extern int devtmpfs_delete_node(struct device *dev);
index 6f8be328770abb3c11166755d9c954194cfac1ae..f4bb378ccf6a355bbe49e79f56019f9ef386d1d4 100644 (file)
@@ -34,7 +34,7 @@
  * re-allowed until epoll_wait is called again after consuming the wakeup
  * event(s).
  *
- * Requires CAP_EPOLLWAKEUP
+ * Requires CAP_BLOCK_SUSPEND
  */
 #define EPOLLWAKEUP (1 << 29)
 
index 58bf158c53d91aca4f7c60a22f0109851aa53b21..a22408bac0d005bca76c99e30a5d88b83e294561 100644 (file)
@@ -39,4 +39,7 @@ extern void put_unused_fd(unsigned int fd);
 
 extern void fd_install(unsigned int fd, struct file *file);
 
+extern void flush_delayed_fput(void);
+extern void __fput_sync(struct file *);
+
 #endif /* __LINUX_FILE_H */
index 17fd887c798f3fff64aaf27bf82a81a2d237ee31..8fabb037a48db40e8a490fc74c15ce907ad9059a 100644 (file)
@@ -826,7 +826,7 @@ struct inode {
        struct list_head        i_lru;          /* inode LRU list */
        struct list_head        i_sb_list;
        union {
-               struct list_head        i_dentry;
+               struct hlist_head       i_dentry;
                struct rcu_head         i_rcu;
        };
        u64                     i_version;
@@ -1571,7 +1571,7 @@ extern void unlock_super(struct super_block *);
 /*
  * VFS helper functions..
  */
-extern int vfs_create(struct inode *, struct dentry *, umode_t, struct nameidata *);
+extern int vfs_create(struct inode *, struct dentry *, umode_t, bool);
 extern int vfs_mkdir(struct inode *, struct dentry *, umode_t);
 extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, const char *);
@@ -1666,7 +1666,7 @@ struct file_operations {
 };
 
 struct inode_operations {
-       struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
+       struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
        void * (*follow_link) (struct dentry *, struct nameidata *);
        int (*permission) (struct inode *, int);
        struct posix_acl * (*get_acl)(struct inode *, int);
@@ -1674,7 +1674,7 @@ struct inode_operations {
        int (*readlink) (struct dentry *, char __user *,int);
        void (*put_link) (struct dentry *, struct nameidata *, void *);
 
-       int (*create) (struct inode *,struct dentry *,umode_t,struct nameidata *);
+       int (*create) (struct inode *,struct dentry *, umode_t, bool);
        int (*link) (struct dentry *,struct inode *,struct dentry *);
        int (*unlink) (struct inode *,struct dentry *);
        int (*symlink) (struct inode *,struct dentry *,const char *);
@@ -1693,6 +1693,9 @@ struct inode_operations {
        int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
                      u64 len);
        int (*update_time)(struct inode *, struct timespec *, int);
+       int (*atomic_open)(struct inode *, struct dentry *,
+                          struct file *, unsigned open_flag,
+                          umode_t create_mode, int *opened);
 } ____cacheline_aligned;
 
 struct seq_file;
@@ -1911,7 +1914,7 @@ void free_anon_bdev(dev_t);
 struct super_block *sget(struct file_system_type *type,
                        int (*test)(struct super_block *,void *),
                        int (*set)(struct super_block *,void *),
-                       void *data);
+                       int flags, void *data);
 extern struct dentry *mount_pseudo(struct file_system_type *, char *,
        const struct super_operations *ops,
        const struct dentry_operations *dops,
@@ -2057,10 +2060,17 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags,
 extern struct file *filp_open(const char *, int, umode_t);
 extern struct file *file_open_root(struct dentry *, struct vfsmount *,
                                   const char *, int);
-extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
-                                const struct cred *);
+extern struct file * dentry_open(const struct path *, int, const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
 extern char * getname(const char __user *);
+enum {
+       FILE_CREATED = 1,
+       FILE_OPENED = 2
+};
+extern int finish_open(struct file *file, struct dentry *dentry,
+                       int (*open)(struct inode *, struct file *),
+                       int *opened);
+extern int finish_no_open(struct file *file, struct dentry *dentry);
 
 /* fs/ioctl.c */
 
@@ -2091,6 +2101,7 @@ extern sector_t blkdev_max_block(struct block_device *bdev);
 extern void bd_forget(struct inode *inode);
 extern void bdput(struct block_device *);
 extern void invalidate_bdev(struct block_device *);
+extern void iterate_bdevs(void (*)(struct block_device *, void *), void *);
 extern int sync_blockdev(struct block_device *bdev);
 extern void kill_bdev(struct block_device *);
 extern struct super_block *freeze_bdev(struct block_device *);
@@ -2112,6 +2123,10 @@ static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb)
 {
        return 0;
 }
+
+static inline void iterate_bdevs(void (*f)(struct block_device *, void *), void *arg)
+{
+}
 #endif
 extern int sync_filesystem(struct super_block *);
 extern const struct file_operations def_blk_fops;
@@ -2438,7 +2453,7 @@ extern loff_t noop_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
-               int origin, loff_t maxsize);
+               int origin, loff_t maxsize, loff_t eof);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 extern int nonseekable_open(struct inode * inode, struct file * filp);
 
@@ -2560,7 +2575,7 @@ extern int simple_write_end(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned copied,
                        struct page *page, void *fsdata);
 
-extern struct dentry *simple_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
 extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern const struct file_operations simple_dir_operations;
 extern const struct inode_operations simple_dir_inode_operations;
index 176a939d15474cf73baff4b1d0020c2e1212d19b..af961d6f7ab14edc6b3a0c8ec813124fba5415da 100644 (file)
@@ -65,7 +65,7 @@ struct trace_iterator {
        void                    *private;
        int                     cpu_file;
        struct mutex            mutex;
-       struct ring_buffer_iter *buffer_iter[NR_CPUS];
+       struct ring_buffer_iter **buffer_iter;
        unsigned long           iter_flags;
 
        /* trace_seq for __print_flags() and __print_symbolic() etc. */
@@ -207,6 +207,9 @@ struct ftrace_event_call {
         *   bit 1:             enabled
         *   bit 2:             filter_active
         *   bit 3:             enabled cmd record
+        *   bit 4:             allow trace by non root (cap any)
+        *   bit 5:             failed to apply filter
+        *   bit 6:             ftrace internal event (do not enable)
         *
         * Changes to flags must hold the event_mutex.
         *
index f07fc2d081598ba7c2432a2306081473d3e0bbe1..2e31e8b3a190bb652bb597104139d2f2b440d347 100644 (file)
@@ -22,8 +22,8 @@
 /* Gpio pin is open source */
 #define GPIOF_OPEN_SOURCE      (1 << 3)
 
-#define GPIOF_EXPORT           (1 << 2)
-#define GPIOF_EXPORT_CHANGEABLE        (1 << 3)
+#define GPIOF_EXPORT           (1 << 4)
+#define GPIOF_EXPORT_CHANGEABLE        (1 << 5)
 #define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT)
 #define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
 
index fd0dc30c9f154af94155b8c8c47e0a228fbd2573..cc07d2777bbe6b11a632840c5f0a867436bbeac5 100644 (file)
@@ -165,6 +165,7 @@ enum  hrtimer_base_type {
  * @lock:              lock protecting the base and associated clock bases
  *                     and timers
  * @active_bases:      Bitfield to mark bases with active timers
+ * @clock_was_set:     Indicates that clock was set from irq context.
  * @expires_next:      absolute time of the next event which was scheduled
  *                     via clock_set_next_event()
  * @hres_active:       State of high resolution mode
@@ -177,7 +178,8 @@ enum  hrtimer_base_type {
  */
 struct hrtimer_cpu_base {
        raw_spinlock_t                  lock;
-       unsigned long                   active_bases;
+       unsigned int                    active_bases;
+       unsigned int                    clock_was_set;
 #ifdef CONFIG_HIGH_RES_TIMERS
        ktime_t                         expires_next;
        int                             hres_active;
@@ -286,6 +288,8 @@ extern void hrtimer_peek_ahead_timers(void);
 # define MONOTONIC_RES_NSEC    HIGH_RES_NSEC
 # define KTIME_MONOTONIC_RES   KTIME_HIGH_RES
 
+extern void clock_was_set_delayed(void);
+
 #else
 
 # define MONOTONIC_RES_NSEC    LOW_RES_NSEC
@@ -306,6 +310,9 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
 {
        return 0;
 }
+
+static inline void clock_was_set_delayed(void) { }
+
 #endif
 
 extern void clock_was_set(void);
@@ -320,6 +327,7 @@ extern ktime_t ktime_get(void);
 extern ktime_t ktime_get_real(void);
 extern ktime_t ktime_get_boottime(void);
 extern ktime_t ktime_get_monotonic_offset(void);
+extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot);
 
 DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
 
index 3993477103a5673e65f69a751ba302d5c03b0a0e..555382660bc40e00eb4876eae585f3f9a5e6eea6 100644 (file)
@@ -683,7 +683,6 @@ struct twl4030_audio_data {
 };
 
 struct twl4030_platform_data {
-       unsigned                                irq_base, irq_end;
        struct twl4030_clock_init_data          *clock;
        struct twl4030_bci_platform_data        *bci;
        struct twl4030_gpio_platform_data       *gpio;
index 9e65eff6af3bdc5dd6e865296233c8f9a1cd2a10..8a74761869908ea56a3e840f2f0fa9a98df20de5 100644 (file)
@@ -168,8 +168,8 @@ extern struct cred init_cred;
        .children       = LIST_HEAD_INIT(tsk.children),                 \
        .sibling        = LIST_HEAD_INIT(tsk.sibling),                  \
        .group_leader   = &tsk,                                         \
-       RCU_INIT_POINTER(.real_cred, &init_cred),                       \
-       RCU_INIT_POINTER(.cred, &init_cred),                            \
+       RCU_POINTER_INITIALIZER(real_cred, &init_cred),                 \
+       RCU_POINTER_INITIALIZER(cred, &init_cred),                      \
        .comm           = INIT_TASK_COMM,                               \
        .thread         = INIT_THREAD,                                  \
        .fs             = &init_fs,                                     \
index a81671453575d800ec3d102e1aa6a8bf517073ce..2740d080ec6b7607fa1daba2bb2f72395fe34a7f 100644 (file)
@@ -116,6 +116,7 @@ struct input_keymap_entry {
 
 /**
  * EVIOCGMTSLOTS(len) - get MT slot values
+ * @len: size of the data buffer in bytes
  *
  * The ioctl buffer argument should be binary equivalent to
  *
index e6ca56de99364fb435a7bf2932a1cf5e37e3146b..78e2ada50cd5a95c7b7527777a870428afa5352c 100644 (file)
@@ -308,6 +308,8 @@ enum {
 
 struct intel_iommu {
        void __iomem    *reg; /* Pointer to hardware regs, virtual addr */
+       u64             reg_phys; /* physical address of hw register set */
+       u64             reg_size; /* size of hw register set */
        u64             cap;
        u64             ecap;
        u32             gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
index a5261e3d2e3c26f3cf645af875e4093d5adcaa77..553fb66da130a3a9b3700958c5cce22a6b5cda73 100644 (file)
@@ -150,9 +150,7 @@ struct irq_data {
        void                    *handler_data;
        void                    *chip_data;
        struct msi_desc         *msi_desc;
-#ifdef CONFIG_SMP
        cpumask_var_t           affinity;
-#endif
 };
 
 /*
index c513a40510f534f3136b015f8fafa2d597b18099..0976fc46d1e0143b1a167cde02e2026e54ba8db2 100644 (file)
@@ -42,8 +42,7 @@
  * allowed.
  *
  * Not initializing the key (static data is initialized to 0s anyway) is the
- * same as using STATIC_KEY_INIT_FALSE and static_key_false() is
- * equivalent with static_branch().
+ * same as using STATIC_KEY_INIT_FALSE.
  *
 */
 
@@ -107,12 +106,6 @@ static __always_inline bool static_key_true(struct static_key *key)
        return !static_key_false(key);
 }
 
-/* Deprecated. Please use 'static_key_false() instead. */
-static __always_inline bool static_branch(struct static_key *key)
-{
-       return arch_static_branch(key);
-}
-
 extern struct jump_entry __start___jump_table[];
 extern struct jump_entry __stop___jump_table[];
 
@@ -166,14 +159,6 @@ static __always_inline bool static_key_true(struct static_key *key)
        return false;
 }
 
-/* Deprecated. Please use 'static_key_false() instead. */
-static __always_inline bool static_branch(struct static_key *key)
-{
-       if (unlikely(atomic_read(&key->enabled)) > 0)
-               return true;
-       return false;
-}
-
 static inline void static_key_slow_inc(struct static_key *key)
 {
        atomic_inc(&key->enabled);
index e07f5e0c5df4400eb34ac0d89150003e512381b0..604382143bcfccd6772260ed56e16589800af83c 100644 (file)
@@ -377,7 +377,6 @@ extern enum system_states {
        SYSTEM_HALT,
        SYSTEM_POWER_OFF,
        SYSTEM_RESTART,
-       SYSTEM_SUSPEND_DISK,
 } system_state;
 
 #define TAINT_PROPRIETARY_MODULE       0
index 4cd22ed627efd79205860b0efa6dde15a07897ed..cef3b315ba7c2e0786e78940cc476c8e12bc89ce 100644 (file)
@@ -303,7 +303,9 @@ static inline bool key_is_instantiated(const struct key *key)
                                   rwsem_is_locked(&((struct key *)(KEY))->sem)))
 
 #define rcu_assign_keypointer(KEY, PAYLOAD)                            \
-       (rcu_assign_pointer((KEY)->payload.rcudata, PAYLOAD))
+do {                                                                   \
+       rcu_assign_pointer((KEY)->payload.rcudata, (PAYLOAD));          \
+} while (0)
 
 #ifdef CONFIG_SYSCTL
 extern ctl_table key_sysctls[];
index d6bd50110ec2f80956ada720336052b0e1d685f7..2e7a1e032c71a91e6a9dff98a0b637d621932a25 100644 (file)
@@ -55,12 +55,17 @@ struct kmsg_dumper {
 #ifdef CONFIG_PRINTK
 void kmsg_dump(enum kmsg_dump_reason reason);
 
+bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
+                              char *line, size_t size, size_t *len);
+
 bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
                        char *line, size_t size, size_t *len);
 
 bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
                          char *buf, size_t size, size_t *len);
 
+void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper);
+
 void kmsg_dump_rewind(struct kmsg_dumper *dumper);
 
 int kmsg_dump_register(struct kmsg_dumper *dumper);
@@ -71,6 +76,13 @@ static inline void kmsg_dump(enum kmsg_dump_reason reason)
 {
 }
 
+static inline bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper,
+                                            bool syslog, const char *line,
+                                            size_t size, size_t *len)
+{
+       return false;
+}
+
 static inline bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
                                const char *line, size_t size, size_t *len)
 {
@@ -83,6 +95,10 @@ static inline bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        return false;
 }
 
+static inline void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
+{
+}
+
 static inline void kmsg_dump_rewind(struct kmsg_dumper *dumper)
 {
 }
index c4464356b35b0af21eaafe6cbd1d2d7b4f549814..96c158a37d3e5ead53765e4bfa2280a82c79be5e 100644 (file)
@@ -815,7 +815,7 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
 #ifdef CONFIG_HAVE_KVM_EVENTFD
 
 void kvm_eventfd_init(struct kvm *kvm);
-int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags);
+int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args);
 void kvm_irqfd_release(struct kvm *kvm);
 void kvm_irq_routing_update(struct kvm *, struct kvm_irq_routing_table *);
 int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
@@ -824,7 +824,7 @@ int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
 
 static inline void kvm_eventfd_init(struct kvm *kvm) {}
 
-static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
+static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
 {
        return -EINVAL;
 }
index a6bb102351486a15a8e1bce8a2da4fbfea4037c6..19dc455b4f3dd072d0e58abdfed2de6f8ae5727c 100644 (file)
@@ -50,9 +50,7 @@ phys_addr_t memblock_find_in_range_node(phys_addr_t start, phys_addr_t end,
                                phys_addr_t size, phys_addr_t align, int nid);
 phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
                                   phys_addr_t size, phys_addr_t align);
-int memblock_free_reserved_regions(void);
-int memblock_reserve_reserved_regions(void);
-
+phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr);
 void memblock_allow_resize(void);
 int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid);
 int memblock_add(phys_addr_t base, phys_addr_t size);
index 21603b42f22fb150f73a5be185e6c1d615de6329..0b2e0ed309f51038583a23f168383ab6e6a6f72c 100644 (file)
@@ -347,6 +347,7 @@ struct s5m_platform_data {
        bool                            buck_voltage_lock;
 
        int                             buck_gpios[3];
+       int                             buck_ds[3];
        int                             buck2_voltage[8];
        bool                            buck2_gpiodvs;
        int                             buck3_voltage[8];
@@ -369,6 +370,10 @@ struct s5m_platform_data {
        bool                            buck2_ramp_enable;
        bool                            buck3_ramp_enable;
        bool                            buck4_ramp_enable;
+
+       int                             buck2_init;
+       int                             buck3_init;
+       int                             buck4_init;
 };
 
 #endif /*  __LINUX_MFD_S5M_CORE_H */
index f5171dbf8850c5c036e2e431ade03382bbe21983..d83af39815abca0e17f8282b92791289fec15007 100644 (file)
@@ -101,6 +101,7 @@ struct tmio_mmc_host;
 struct tmio_mmc_data {
        unsigned int                    hclk;
        unsigned long                   capabilities;
+       unsigned long                   capabilities2;
        unsigned long                   flags;
        u32                             ocr_mask;       /* available voltages */
        struct tmio_mmc_dma             *dma;
@@ -110,6 +111,9 @@ struct tmio_mmc_data {
        void (*set_clk_div)(struct platform_device *host, int state);
        int (*get_cd)(struct platform_device *host);
        int (*write16_hook)(struct tmio_mmc_host *host, int addr);
+       /* clock management callbacks */
+       int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
+       void (*clk_disable)(struct platform_device *pdev);
 };
 
 /*
index e030ef9a64eede0ca1bc8ca529a6788624c6017c..12c06870829af2add4caed14a9ea57f069b7479f 100644 (file)
@@ -217,7 +217,8 @@ enum tps65217_regulator_id {
  * Board data may be used to initialize regulator.
  */
 struct tps65217_board {
-       struct regulator_init_data *tps65217_init_data;
+       struct regulator_init_data *tps65217_init_data[TPS65217_NUM_REGULATOR];
+       struct device_node *of_node[TPS65217_NUM_REGULATOR];
 };
 
 /**
@@ -227,11 +228,6 @@ struct tps65217_board {
  * @max_uV:            minimum micro volts
  * @vsel_to_uv:                Function pointer to get voltage from selector
  * @uv_to_vsel:                Function pointer to get selector from voltage
- * @table:             Table for non-uniform voltage step-size
- * @table_len:         Length of the voltage table
- * @enable_mask:       Regulator enable mask bits
- * @set_vout_reg:      Regulator output voltage set register
- * @set_vout_mask:     Regulator output voltage set mask
  *
  * This data is used to check the regualtor voltage limits while setting.
  */
@@ -241,11 +237,6 @@ struct tps_info {
        int max_uV;
        int (*vsel_to_uv)(unsigned int vsel);
        int (*uv_to_vsel)(int uV, unsigned int *vsel);
-       const int *table;
-       unsigned int table_len;
-       unsigned int enable_mask;
-       unsigned int set_vout_reg;
-       unsigned int set_vout_mask;
 };
 
 /**
index dd8dc0a6c46243141ea59e325cde465fb993bce5..6c4c478e21a4f79d33577db36faba4e9f37f3cd3 100644 (file)
@@ -880,4 +880,10 @@ static inline int tps65910_reg_clear_bits(struct tps65910 *tps65910, u8 reg,
        return regmap_update_bits(tps65910->regmap, reg, mask, 0);
 }
 
+static inline int tps65910_reg_update_bits(struct tps65910 *tps65910, u8 reg,
+                                          u8 mask, u8 val)
+{
+       return regmap_update_bits(tps65910->regmap, reg, mask, val);
+}
+
 #endif /*  __LINUX_MFD_TPS65910_H */
index b36d08ce5c578dcd18e224828217ded481de54ee..f9f279cf5b1bd558520aa23757cb53e0928a18a3 100644 (file)
@@ -1591,6 +1591,7 @@ void vmemmap_populate_print_last(void);
 enum mf_flags {
        MF_COUNT_INCREASED = 1 << 0,
        MF_ACTION_REQUIRED = 1 << 1,
+       MF_MUST_KILL = 1 << 2,
 };
 extern int memory_failure(unsigned long pfn, int trapno, int flags);
 extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
index d76513b5b2631b1daf7b9aa4c4b03f1d52d83d32..111aca5e97f3d1801ace7ed7c009af4165a3869a 100644 (file)
@@ -149,6 +149,7 @@ struct sd_switch_caps {
 #define SD_SET_CURRENT_LIMIT_400       1
 #define SD_SET_CURRENT_LIMIT_600       2
 #define SD_SET_CURRENT_LIMIT_800       3
+#define SD_SET_CURRENT_NO_CHANGE       (-1)
 
 #define SD_MAX_CURRENT_200     (1 << SD_SET_CURRENT_LIMIT_200)
 #define SD_MAX_CURRENT_400     (1 << SD_SET_CURRENT_LIMIT_400)
diff --git a/include/linux/mmc/cd-gpio.h b/include/linux/mmc/cd-gpio.h
deleted file mode 100644 (file)
index cefaba0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Generic GPIO card-detect helper header
- *
- * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef MMC_CD_GPIO_H
-#define MMC_CD_GPIO_H
-
-struct mmc_host;
-int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio);
-void mmc_cd_gpio_free(struct mmc_host *host);
-
-#endif
index 0707d228d7f11d675743aa8d58b5b5c05274295f..f578a71d82a6b71bd1c9203b53e77713c4543065 100644 (file)
@@ -11,6 +11,7 @@
 #define LINUX_MMC_HOST_H
 
 #include <linux/leds.h>
+#include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/fault-inject.h>
@@ -150,11 +151,31 @@ struct mmc_async_req {
        int (*err_check) (struct mmc_card *, struct mmc_async_req *);
 };
 
-struct mmc_hotplug {
-       unsigned int irq;
+/**
+ * struct mmc_slot - MMC slot functions
+ *
+ * @cd_irq:            MMC/SD-card slot hotplug detection IRQ or -EINVAL
+ * @lock:              protect the @handler_priv pointer
+ * @handler_priv:      MMC/SD-card slot context
+ *
+ * Some MMC/SD host controllers implement slot-functions like card and
+ * write-protect detection natively. However, a large number of controllers
+ * leave these functions to the CPU. This struct provides a hook to attach
+ * such slot-function drivers.
+ */
+struct mmc_slot {
+       int cd_irq;
+       struct mutex lock;
        void *handler_priv;
 };
 
+struct regulator;
+
+struct mmc_supply {
+       struct regulator *vmmc;         /* Card power supply */
+       struct regulator *vqmmc;        /* Optional Vccq supply */
+};
+
 struct mmc_host {
        struct device           *parent;
        struct device           class_dev;
@@ -168,6 +189,9 @@ struct mmc_host {
        u32                     ocr_avail_sd;   /* SD-specific OCR */
        u32                     ocr_avail_mmc;  /* MMC-specific OCR */
        struct notifier_block   pm_notify;
+       u32                     max_current_330;
+       u32                     max_current_300;
+       u32                     max_current_180;
 
 #define MMC_VDD_165_195                0x00000080      /* VDD voltage 1.65 - 1.95 */
 #define MMC_VDD_20_21          0x00000100      /* VDD voltage 2.0 ~ 2.1 */
@@ -211,16 +235,9 @@ struct mmc_host {
 #define MMC_CAP_UHS_SDR50      (1 << 17)       /* Host supports UHS SDR50 mode */
 #define MMC_CAP_UHS_SDR104     (1 << 18)       /* Host supports UHS SDR104 mode */
 #define MMC_CAP_UHS_DDR50      (1 << 19)       /* Host supports UHS DDR50 mode */
-#define MMC_CAP_SET_XPC_330    (1 << 20)       /* Host supports >150mA current at 3.3V */
-#define MMC_CAP_SET_XPC_300    (1 << 21)       /* Host supports >150mA current at 3.0V */
-#define MMC_CAP_SET_XPC_180    (1 << 22)       /* Host supports >150mA current at 1.8V */
 #define MMC_CAP_DRIVER_TYPE_A  (1 << 23)       /* Host supports Driver Type A */
 #define MMC_CAP_DRIVER_TYPE_C  (1 << 24)       /* Host supports Driver Type C */
 #define MMC_CAP_DRIVER_TYPE_D  (1 << 25)       /* Host supports Driver Type D */
-#define MMC_CAP_MAX_CURRENT_200        (1 << 26)       /* Host max current limit is 200mA */
-#define MMC_CAP_MAX_CURRENT_400        (1 << 27)       /* Host max current limit is 400mA */
-#define MMC_CAP_MAX_CURRENT_600        (1 << 28)       /* Host max current limit is 600mA */
-#define MMC_CAP_MAX_CURRENT_800        (1 << 29)       /* Host max current limit is 800mA */
 #define MMC_CAP_CMD23          (1 << 30)       /* CMD23 supported. */
 #define MMC_CAP_HW_RESET       (1 << 31)       /* Hardware reset */
 
@@ -238,6 +255,8 @@ struct mmc_host {
 #define MMC_CAP2_BROKEN_VOLTAGE        (1 << 7)        /* Use the broken voltage */
 #define MMC_CAP2_DETECT_ON_ERR (1 << 8)        /* On I/O err check card removal */
 #define MMC_CAP2_HC_ERASE_SZ   (1 << 9)        /* High-capacity erase size */
+#define MMC_CAP2_CD_ACTIVE_HIGH        (1 << 10)       /* Card-detect signal active high */
+#define MMC_CAP2_RO_ACTIVE_HIGH        (1 << 11)       /* Write-protect signal active high */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
        unsigned int        power_notify_type;
@@ -290,7 +309,7 @@ struct mmc_host {
 
        struct delayed_work     detect;
        int                     detect_change;  /* card detect flag */
-       struct mmc_hotplug      hotplug;
+       struct mmc_slot         slot;
 
        const struct mmc_bus_ops *bus_ops;      /* current bus driver */
        unsigned int            bus_refs;       /* reference counter */
@@ -309,6 +328,7 @@ struct mmc_host {
 #ifdef CONFIG_REGULATOR
        bool                    regulator_enabled; /* regulator state */
 #endif
+       struct mmc_supply       supply;
 
        struct dentry           *debugfs_root;
 
@@ -357,13 +377,12 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
        wake_up_process(host->sdio_irq_thread);
 }
 
-struct regulator;
-
 #ifdef CONFIG_REGULATOR
 int mmc_regulator_get_ocrmask(struct regulator *supply);
 int mmc_regulator_set_ocr(struct mmc_host *mmc,
                        struct regulator *supply,
                        unsigned short vdd_bit);
+int mmc_regulator_get_supply(struct mmc_host *mmc);
 #else
 static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
 {
@@ -376,6 +395,11 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
 {
        return 0;
 }
+
+static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
+{
+       return 0;
+}
 #endif
 
 int mmc_card_awake(struct mmc_host *host);
index e9051e1cb1ce38434d0443cfee5c7c74e43a1967..ac83b105bedd66d2fb051ead198d11297ab650c3 100644 (file)
@@ -122,6 +122,7 @@ struct sdhci_host {
 #define SDHCI_PV_ENABLED       (1<<8)  /* Preset value enabled */
 #define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
 #define SDHCI_HS200_NEEDS_TUNING (1<<10)       /* HS200 needs tuning */
+#define SDHCI_USING_RETUNING_TIMER (1<<11)     /* Host is using a retuning timer for the card */
 
        unsigned int version;   /* SDHCI spec. version */
 
@@ -155,7 +156,8 @@ struct sdhci_host {
 
        struct timer_list timer;        /* Timer for timeouts */
 
-       unsigned int caps;      /* Alternative capabilities */
+       unsigned int caps;      /* Alternative CAPABILITY_0 */
+       unsigned int caps1;     /* Alternative CAPABILITY_1 */
 
        unsigned int            ocr_avail_sdio; /* OCR bit masks */
        unsigned int            ocr_avail_sd;
index 05f0e3db1c12b6681a820ff48519b0abe03b983b..c2f73cbb4d5cb14912a01efa59983b21e5ff081a 100644 (file)
@@ -44,6 +44,8 @@ struct sh_mmcif_plat_data {
        struct sh_mmcif_dma     *dma;           /* Deprecated. Instead */
        unsigned int            slave_id_tx;    /* use embedded slave_id_[tr]x */
        unsigned int            slave_id_rx;
+       bool                    use_cd_gpio : 1;
+       unsigned int            cd_gpio;
        u8                      sup_pclk;       /* 1 :SH7757, 0: SH7724/SH7372 */
        unsigned long           caps;
        u32                     ocr;
index e94e620aeddc01a49b4f6073f54400ff343e66e2..b65679ffa880a3fae58ae49fa574aedeb9dfd333 100644 (file)
@@ -23,6 +23,7 @@ struct sh_mobile_sdhi_info {
        int dma_slave_rx;
        unsigned long tmio_flags;
        unsigned long tmio_caps;
+       unsigned long tmio_caps2;
        u32 tmio_ocr_mask;      /* available MMC voltages */
        unsigned int cd_gpio;
        struct tmio_mmc_data *pdata;
diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h
new file mode 100644 (file)
index 0000000..7d88d27
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Generic GPIO card-detect helper header
+ *
+ * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MMC_SLOT_GPIO_H
+#define MMC_SLOT_GPIO_H
+
+struct mmc_host;
+
+int mmc_gpio_get_ro(struct mmc_host *host);
+int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio);
+void mmc_gpio_free_ro(struct mmc_host *host);
+
+int mmc_gpio_get_cd(struct mmc_host *host);
+int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio);
+void mmc_gpio_free_cd(struct mmc_host *host);
+
+#endif
index 2427706f78b4d7043b5476b310d5a203631dbf90..68c569fcbb66ff751d689c57e19f196d33b2b0f8 100644 (file)
@@ -694,7 +694,7 @@ typedef struct pglist_data {
                                             range, including holes */
        int node_id;
        wait_queue_head_t kswapd_wait;
-       struct task_struct *kswapd;
+       struct task_struct *kswapd;     /* Protected by lock_memory_hotplug() */
        int kswapd_max_order;
        enum zone_type classzone_idx;
 } pg_data_t;
similarity index 95%
rename from arch/arm/mach-mxs/include/mach/mxsfb.h
rename to include/linux/mxsfb.h
index e4d79791515eab85060b6c2695c05116bf6d49ff..f14943d55315695e36186a75c5db56f07407dd20 100644 (file)
@@ -14,8 +14,8 @@
  * MA 02110-1301, USA.
  */
 
-#ifndef __MACH_FB_H
-#define __MACH_FB_H
+#ifndef __LINUX_MXSFB_H
+#define __LINUX_MXSFB_H
 
 #include <linux/fb.h>
 
@@ -46,4 +46,4 @@ struct mxsfb_platform_data {
                                 */
 };
 
-#endif /* __MACH_FB_H */
+#endif /* __LINUX_MXSFB_H */
index ffc02135c483c2c6363eed8dc0a4b15b2def6656..d2ef8b34b96722078c5ab7a3914579d5b50a8ca6 100644 (file)
@@ -7,12 +7,6 @@
 
 struct vfsmount;
 
-struct open_intent {
-       int     flags;
-       int     create_mode;
-       struct file *file;
-};
-
 enum { MAX_NESTED_LINKS = 8 };
 
 struct nameidata {
@@ -25,11 +19,6 @@ struct nameidata {
        int             last_type;
        unsigned        depth;
        char *saved_names[MAX_NESTED_LINKS + 1];
-
-       /* Intent data */
-       union {
-               struct open_intent open;
-       } intent;
 };
 
 /*
@@ -78,13 +67,10 @@ extern int kern_path(const char *, unsigned, struct path *);
 
 extern struct dentry *kern_path_create(int, const char *, struct path *, int);
 extern struct dentry *user_path_create(int, const char __user *, struct path *, int);
-extern int kern_path_parent(const char *, struct nameidata *);
+extern struct dentry *kern_path_locked(const char *, struct path *);
 extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
                           const char *, unsigned int, struct path *);
 
-extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
-               int (*open)(struct inode *, struct file *));
-
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 
 extern int follow_down_one(struct path *);
@@ -94,6 +80,8 @@ extern int follow_up(struct path *);
 extern struct dentry *lock_rename(struct dentry *, struct dentry *);
 extern void unlock_rename(struct dentry *, struct dentry *);
 
+extern void nd_jump_link(struct nameidata *nd, struct path *path);
+
 static inline void nd_set_link(struct nameidata *nd, char *path)
 {
        nd->saved_names[nd->depth] = path;
index 8aadd90b808a67b466ceb66cbc0de0b57883e96b..d3b7c18b18f4e068997789bda6cc25be52720f8a 100644 (file)
@@ -1374,7 +1374,7 @@ struct nfs_rpc_ops {
        int     (*readlink)(struct inode *, struct page *, unsigned int,
                            unsigned int);
        int     (*create)  (struct inode *, struct dentry *,
-                           struct iattr *, int, struct nfs_open_context *);
+                           struct iattr *, int);
        int     (*remove)  (struct inode *, struct qstr *);
        void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
        void    (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
index fefb4e19bf6a476a634d5384814d347b1179094c..d8c379dba6adbb36ae9df6c18adea304e2c6b45c 100644 (file)
@@ -176,8 +176,6 @@ 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,
-       /* Device causes system crash if in D3 during S3 sleep */
-       PCI_DEV_FLAGS_NO_D3_DURING_SLEEP = (__force pci_dev_flags_t) 8,
 };
 
 enum pci_irq_reroute_variant {
index ab741b0d007402daf8feee824e0aae91751bafe6..fc35260773489d55724f87d3493f5d5b23ab1f57 100644 (file)
 #define PCI_DEVICE_ID_AMD_11H_NB_DRAM  0x1302
 #define PCI_DEVICE_ID_AMD_11H_NB_MISC  0x1303
 #define PCI_DEVICE_ID_AMD_11H_NB_LINK  0x1304
+#define PCI_DEVICE_ID_AMD_15H_M10H_F3  0x1403
 #define PCI_DEVICE_ID_AMD_15H_NB_F0    0x1600
 #define PCI_DEVICE_ID_AMD_15H_NB_F1    0x1601
 #define PCI_DEVICE_ID_AMD_15H_NB_F2    0x1602
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB7  0x3c27
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB8  0x3c2e
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB9  0x3c2f
+#define PCI_DEVICE_ID_INTEL_UNC_HA     0x3c46
+#define PCI_DEVICE_ID_INTEL_UNC_IMC0   0x3cb0
+#define PCI_DEVICE_ID_INTEL_UNC_IMC1   0x3cb1
+#define PCI_DEVICE_ID_INTEL_UNC_IMC2   0x3cb4
+#define PCI_DEVICE_ID_INTEL_UNC_IMC3   0x3cb5
+#define PCI_DEVICE_ID_INTEL_UNC_QPI0   0x3c41
+#define PCI_DEVICE_ID_INTEL_UNC_QPI1   0x3c42
+#define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43
+#define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44
+#define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45
+#define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX      0x3ce0
 #define PCI_DEVICE_ID_INTEL_IOAT_SNB   0x402f
 #define PCI_DEVICE_ID_INTEL_5100_16    0x65f0
 #define PCI_DEVICE_ID_INTEL_5100_21    0x65f5
index 45db49f64bb492ddf34d2b451fffa810ea45b965..76c5c8b724a77253e3ca635c90e53ed6230b3c5f 100644 (file)
@@ -677,6 +677,7 @@ struct hw_perf_event {
                        u64             last_tag;
                        unsigned long   config_base;
                        unsigned long   event_base;
+                       int             event_base_rdpmc;
                        int             idx;
                        int             last_cpu;
 
@@ -1106,6 +1107,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr,
                                struct task_struct *task,
                                perf_overflow_handler_t callback,
                                void *context);
+extern void perf_pmu_migrate_context(struct pmu *pmu,
+                               int src_cpu, int dst_cpu);
 extern u64 perf_event_read_value(struct perf_event *event,
                                 u64 *enabled, u64 *running);
 
diff --git a/include/linux/platform_data/clk-nomadik.h b/include/linux/platform_data/clk-nomadik.h
new file mode 100644 (file)
index 0000000..5713c87
--- /dev/null
@@ -0,0 +1,2 @@
+/* Minimal platform data header */
+void nomadik_clk_init(void);
index 30f794eb382654f9017b868b4245986b4e621a31..a7d6172922d405c950c701bf4a7d2d21bb4e0c77 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/notifier.h>
+#include <linux/cpuidle.h>
 
 enum gpd_status {
        GPD_STATE_ACTIVE = 0,   /* PM domain is active */
@@ -45,6 +46,11 @@ struct gpd_dev_ops {
        bool (*active_wakeup)(struct device *dev);
 };
 
+struct gpd_cpu_data {
+       unsigned int saved_exit_latency;
+       struct cpuidle_state *idle_state;
+};
+
 struct generic_pm_domain {
        struct dev_pm_domain domain;    /* PM domain operations */
        struct list_head gpd_list_node; /* Node in the global PM domains list */
@@ -75,6 +81,7 @@ struct generic_pm_domain {
        bool max_off_time_changed;
        bool cached_power_down_ok;
        struct device_node *of_node; /* Node in device tree */
+       struct gpd_cpu_data *cpu_data;
 };
 
 static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -105,6 +112,7 @@ struct generic_pm_domain_data {
        struct gpd_timing_data td;
        struct notifier_block nb;
        struct mutex lock;
+       unsigned int refcount;
        bool need_restore;
        bool always_on;
 };
@@ -155,6 +163,8 @@ extern int pm_genpd_add_callbacks(struct device *dev,
                                  struct gpd_dev_ops *ops,
                                  struct gpd_timing_data *td);
 extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td);
+extern int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state);
+extern int genpd_detach_cpuidle(struct generic_pm_domain *genpd);
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
                          struct dev_power_governor *gov, bool is_off);
 
@@ -211,6 +221,14 @@ static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
 {
        return -ENOSYS;
 }
+static inline int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st)
+{
+       return -ENOSYS;
+}
+static inline int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+{
+       return -ENOSYS;
+}
 static inline void pm_genpd_init(struct generic_pm_domain *genpd,
                                 struct dev_power_governor *gov, bool is_off)
 {
index 233149cb19f4ae8af9ad35b7f6d2d5ab5929e288..9924ea1f22e07306f39607e08df8b36244832ab9 100644 (file)
@@ -66,7 +66,7 @@ enum pm_qos_req_action {
 
 static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req)
 {
-       return req->dev != 0;
+       return req->dev != NULL;
 }
 
 int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
index 3988012255dc5bf0562758d703f4124656dbfc31..289760f424aaa3247d2e4f66841334c67295c9ef 100644 (file)
  * Changing LSM security domain is considered a new privilege.  So, for example,
  * asking selinux for a specific new context (e.g. with runcon) will result
  * in execve returning -EPERM.
+ *
+ * See Documentation/prctl/no_new_privs.txt for more details.
  */
 #define PR_SET_NO_NEW_PRIVS    38
 #define PR_GET_NO_NEW_PRIVS    39
index c09fa042b5ea077bb748507fd41e464891bbb7b3..524ede8a160a2d85e426f277131fc803558ec748 100644 (file)
@@ -333,7 +333,7 @@ struct quotactl_ops {
        int (*quota_on)(struct super_block *, int, int, struct path *);
        int (*quota_on_meta)(struct super_block *, int, int);
        int (*quota_off)(struct super_block *, int);
-       int (*quota_sync)(struct super_block *, int, int);
+       int (*quota_sync)(struct super_block *, int);
        int (*get_info)(struct super_block *, int, struct if_dqinfo *);
        int (*set_info)(struct super_block *, int, struct if_dqinfo *);
        int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
index 17b977304a09f8208dad924dc475676bd4a6f5f9..ec6b65feaabac1fef7222dd1ad1bc2d286136983 100644 (file)
@@ -83,7 +83,8 @@ int dquot_quota_on(struct super_block *sb, int type, int format_id,
 int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
        int format_id, int type);
 int dquot_quota_off(struct super_block *sb, int type);
-int dquot_quota_sync(struct super_block *sb, int type, int wait);
+int dquot_writeback_dquots(struct super_block *sb, int type);
+int dquot_quota_sync(struct super_block *sb, int type);
 int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
@@ -255,6 +256,11 @@ static inline int dquot_resume(struct super_block *sb, int type)
 
 #define dquot_file_open                generic_file_open
 
+static inline int dquot_writeback_dquots(struct super_block *sb, int type)
+{
+       return 0;
+}
+
 #endif /* CONFIG_QUOTA */
 
 static inline int dquot_alloc_space_nodirty(struct inode *inode, qsize_t nr)
index 26d1a47591f1534306160811967248ed9ecfcc12..115ead2b51553d78a523c4e62db3cb4b84866cd0 100644 (file)
@@ -147,6 +147,7 @@ extern void synchronize_sched(void);
 
 extern void __rcu_read_lock(void);
 extern void __rcu_read_unlock(void);
+extern void rcu_read_unlock_special(struct task_struct *t);
 void synchronize_rcu(void);
 
 /*
@@ -184,7 +185,6 @@ static inline int rcu_preempt_depth(void)
 /* Internal to kernel */
 extern void rcu_sched_qs(int cpu);
 extern void rcu_bh_qs(int cpu);
-extern void rcu_preempt_note_context_switch(void);
 extern void rcu_check_callbacks(int cpu, int user);
 struct notifier_block;
 extern void rcu_idle_enter(void);
@@ -256,6 +256,10 @@ static inline void destroy_rcu_head_on_stack(struct rcu_head *head)
 }
 #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
+#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP)
+extern int rcu_is_cpu_idle(void);
+#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP) */
+
 #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU)
 bool rcu_lockdep_current_cpu_online(void);
 #else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
@@ -267,15 +271,6 @@ static inline bool rcu_lockdep_current_cpu_online(void)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
-#ifdef CONFIG_PROVE_RCU
-extern int rcu_is_cpu_idle(void);
-#else /* !CONFIG_PROVE_RCU */
-static inline int rcu_is_cpu_idle(void)
-{
-       return 0;
-}
-#endif /* else !CONFIG_PROVE_RCU */
-
 static inline void rcu_lock_acquire(struct lockdep_map *map)
 {
        lock_acquire(map, 0, 0, 2, 1, NULL, _THIS_IP_);
@@ -432,8 +427,7 @@ extern int rcu_my_thread_group_empty(void);
 static inline void rcu_preempt_sleep_check(void)
 {
        rcu_lockdep_assert(!lock_is_held(&rcu_lock_map),
-                          "Illegal context switch in RCU read-side "
-                          "critical section");
+                          "Illegal context switch in RCU read-side critical section");
 }
 #else /* #ifdef CONFIG_PROVE_RCU */
 static inline void rcu_preempt_sleep_check(void)
@@ -514,10 +508,10 @@ static inline void rcu_preempt_sleep_check(void)
                (_________p1); \
        })
 #define __rcu_assign_pointer(p, v, space) \
-       ({ \
+       do { \
                smp_wmb(); \
                (p) = (typeof(*v) __force space *)(v); \
-       })
+       } while (0)
 
 
 /**
@@ -852,7 +846,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
  *
  * Assigns the specified value to the specified RCU-protected
  * pointer, ensuring that any concurrent RCU readers will see
- * any prior initialization.  Returns the value assigned.
+ * any prior initialization.
  *
  * Inserts memory barriers on architectures that require them
  * (which is most of them), and also prevents the compiler from
@@ -904,25 +898,17 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
  * the reader-accessible portions of the linked structure.
  */
 #define RCU_INIT_POINTER(p, v) \
-               p = (typeof(*v) __force __rcu *)(v)
-
-static __always_inline bool __is_kfree_rcu_offset(unsigned long offset)
-{
-       return offset < 4096;
-}
-
-static __always_inline
-void __kfree_rcu(struct rcu_head *head, unsigned long offset)
-{
-       typedef void (*rcu_callback)(struct rcu_head *);
-
-       BUILD_BUG_ON(!__builtin_constant_p(offset));
-
-       /* See the kfree_rcu() header comment. */
-       BUILD_BUG_ON(!__is_kfree_rcu_offset(offset));
+       do { \
+               p = (typeof(*v) __force __rcu *)(v); \
+       } while (0)
 
-       kfree_call_rcu(head, (rcu_callback)offset);
-}
+/**
+ * RCU_POINTER_INITIALIZER() - statically initialize an RCU protected pointer
+ *
+ * GCC-style initialization for an RCU-protected pointer in a structure field.
+ */
+#define RCU_POINTER_INITIALIZER(p, v) \
+               .p = (typeof(*v) __force __rcu *)(v)
 
 /*
  * Does the specified offset indicate that the corresponding rcu_head
@@ -936,7 +922,7 @@ void __kfree_rcu(struct rcu_head *head, unsigned long offset)
 #define __kfree_rcu(head, offset) \
        do { \
                BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \
-               call_rcu(head, (void (*)(struct rcu_head *))(unsigned long)(offset)); \
+               kfree_call_rcu(head, (void (*)(struct rcu_head *))(unsigned long)(offset)); \
        } while (0)
 
 /**
index 854dc4c5c27151adeaba69ddd98ac2b91831c1d4..4e56a9c69a356ca73fcd06cf775f337276f77f2e 100644 (file)
@@ -87,6 +87,10 @@ static inline void kfree_call_rcu(struct rcu_head *head,
 
 #ifdef CONFIG_TINY_RCU
 
+static inline void rcu_preempt_note_context_switch(void)
+{
+}
+
 static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
 {
        *delta_jiffies = ULONG_MAX;
@@ -95,6 +99,7 @@ static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
 
 #else /* #ifdef CONFIG_TINY_RCU */
 
+void rcu_preempt_note_context_switch(void);
 int rcu_preempt_needs_cpu(void);
 
 static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
@@ -108,6 +113,7 @@ static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
 static inline void rcu_note_context_switch(int cpu)
 {
        rcu_sched_qs(cpu);
+       rcu_preempt_note_context_switch();
 }
 
 /*
index 56af22ec9aba3e85aa32e035897b90b1b12cc67d..7f7e00df3adf9991ce844a280c4c5c03a9d7bcb6 100644 (file)
  */
 
 #include <linux/list.h>
+#include <linux/rbtree.h>
 
 struct module;
 struct device;
 struct i2c_client;
 struct spi_device;
 struct regmap;
+struct regmap_range_cfg;
 
 /* An enum of all the supported cache types */
 enum regcache_type {
@@ -43,6 +45,14 @@ struct reg_default {
 
 #ifdef CONFIG_REGMAP
 
+enum regmap_endian {
+       /* Unspecified -> 0 -> Backwards compatible default */
+       REGMAP_ENDIAN_DEFAULT = 0,
+       REGMAP_ENDIAN_BIG,
+       REGMAP_ENDIAN_LITTLE,
+       REGMAP_ENDIAN_NATIVE,
+};
+
 /**
  * Configuration for the register map of a device.
  *
@@ -84,6 +94,15 @@ struct reg_default {
  * @reg_defaults_raw: Power on reset values for registers (for use with
  *                    register cache support).
  * @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
+ * @reg_format_endian: Endianness for formatted register addresses. If this is
+ *                     DEFAULT, the @reg_format_endian_default value from the
+ *                     regmap bus is used.
+ * @val_format_endian: Endianness for formatted register values. If this is
+ *                     DEFAULT, the @reg_format_endian_default value from the
+ *                     regmap bus is used.
+ *
+ * @ranges: Array of configuration entries for virtual address ranges.
+ * @num_ranges: Number of range configuration entries.
  */
 struct regmap_config {
        const char *name;
@@ -109,6 +128,43 @@ struct regmap_config {
        u8 write_flag_mask;
 
        bool use_single_rw;
+
+       enum regmap_endian reg_format_endian;
+       enum regmap_endian val_format_endian;
+
+       const struct regmap_range_cfg *ranges;
+       unsigned int n_ranges;
+};
+
+/**
+ * Configuration for indirectly accessed or paged registers.
+ * Registers, mapped to this virtual range, are accessed in two steps:
+ *     1. page selector register update;
+ *     2. access through data window registers.
+ *
+ * @range_min: Address of the lowest register address in virtual range.
+ * @range_max: Address of the highest register in virtual range.
+ *
+ * @page_sel_reg: Register with selector field.
+ * @page_sel_mask: Bit shift for selector value.
+ * @page_sel_shift: Bit mask for selector value.
+ *
+ * @window_start: Address of first (lowest) register in data window.
+ * @window_len: Number of registers in data window.
+ */
+struct regmap_range_cfg {
+       /* Registers of virtual address range */
+       unsigned int range_min;
+       unsigned int range_max;
+
+       /* Page selector for indirect addressing */
+       unsigned int selector_reg;
+       unsigned int selector_mask;
+       int selector_shift;
+
+       /* Data window (per each page) */
+       unsigned int window_start;
+       unsigned int window_len;
 };
 
 typedef int (*regmap_hw_write)(void *context, const void *data,
@@ -133,6 +189,12 @@ typedef void (*regmap_hw_free_context)(void *context);
  *         data.
  * @read_flag_mask: Mask to be set in the top byte of the register when doing
  *                  a read.
+ * @reg_format_endian_default: Default endianness for formatted register
+ *     addresses. Used when the regmap_config specifies DEFAULT. If this is
+ *     DEFAULT, BIG is assumed.
+ * @val_format_endian_default: Default endianness for formatted register
+ *     values. Used when the regmap_config specifies DEFAULT. If this is
+ *     DEFAULT, BIG is assumed.
  */
 struct regmap_bus {
        bool fast_io;
@@ -141,6 +203,8 @@ struct regmap_bus {
        regmap_hw_read read;
        regmap_hw_free_context free_context;
        u8 read_flag_mask;
+       enum regmap_endian reg_format_endian_default;
+       enum regmap_endian val_format_endian_default;
 };
 
 struct regmap *regmap_init(struct device *dev,
@@ -219,6 +283,7 @@ struct regmap_irq {
  * @status_base: Base status register address.
  * @mask_base:   Base mask register address.
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
+ * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
  *
  * @num_regs:    Number of registers in each control bank.
@@ -232,6 +297,7 @@ struct regmap_irq_chip {
        unsigned int status_base;
        unsigned int mask_base;
        unsigned int ack_base;
+       unsigned int wake_base;
        unsigned int irq_reg_stride;
 
        int num_regs;
@@ -243,7 +309,7 @@ struct regmap_irq_chip {
 struct regmap_irq_chip_data;
 
 int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
-                       int irq_base, struct regmap_irq_chip *chip,
+                       int irq_base, const struct regmap_irq_chip *chip,
                        struct regmap_irq_chip_data **data);
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
@@ -361,7 +427,6 @@ static inline int regmap_register_patch(struct regmap *map,
 static inline struct regmap *dev_get_regmap(struct device *dev,
                                            const char *name)
 {
-       WARN_ONCE(1, "regmap API is disabled");
        return NULL;
 }
 
index 4ed1b30ac5fc9ff04cf2a50b1b4ba91e1718e2b7..da339fd8c7559de74ad46dd3536f4b95981c89d8 100644 (file)
@@ -290,6 +290,12 @@ static inline int regulator_set_voltage(struct regulator *regulator,
 }
 
 static inline int regulator_get_voltage(struct regulator *regulator)
+{
+       return -EINVAL;
+}
+
+static inline int regulator_is_supported_voltage(struct regulator *regulator,
+                                  int min_uV, int max_uV)
 {
        return 0;
 }
index b0432cc2b16958809bdd66a8ce6d0c65d7b4a881..bac4c871f3bd1930b481c214e932cec9666e05b6 100644 (file)
@@ -32,6 +32,8 @@ enum regulator_status {
        REGULATOR_STATUS_NORMAL,
        REGULATOR_STATUS_IDLE,
        REGULATOR_STATUS_STANDBY,
+       /* in case that any other status doesn't apply */
+       REGULATOR_STATUS_UNDEFINED,
 };
 
 /**
@@ -67,6 +69,8 @@ enum regulator_status {
  *
  * @enable_time: Time taken for the regulator voltage output voltage to
  *               stabilise after being enabled, in microseconds.
+ * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
+ *             select ramp delay equal to or less than(closest) ramp_delay.
  * @set_voltage_time_sel: Time taken for the regulator voltage output voltage
  *               to stabilise after being set to a new value, in microseconds.
  *               The function provides the from and to voltage selector, the
@@ -113,6 +117,7 @@ struct regulator_ops {
 
        /* Time taken to enable or set voltage on the regulator */
        int (*enable_time) (struct regulator_dev *);
+       int (*set_ramp_delay) (struct regulator_dev *, int ramp_delay);
        int (*set_voltage_time_sel) (struct regulator_dev *,
                                     unsigned int old_selector,
                                     unsigned int new_selector);
@@ -170,11 +175,15 @@ enum regulator_type {
  *
  * @min_uV: Voltage given by the lowest selector (if linear mapping)
  * @uV_step: Voltage increase with each selector (if linear mapping)
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
+ * @volt_table: Voltage mapping table (if table based mapping)
  *
  * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
  * @vsel_mask: Mask for register bitfield used for selector
  * @enable_reg: Register for control when using regmap enable/disable ops
  * @enable_mask: Mask for control when using regmap enable/disable ops
+ *
+ * @enable_time: Time taken for initial enable of regulator (in uS).
  */
 struct regulator_desc {
        const char *name;
@@ -188,11 +197,16 @@ struct regulator_desc {
 
        unsigned int min_uV;
        unsigned int uV_step;
+       unsigned int ramp_delay;
+
+       const unsigned int *volt_table;
 
        unsigned int vsel_reg;
        unsigned int vsel_mask;
        unsigned int enable_reg;
        unsigned int enable_mask;
+
+       unsigned int enable_time;
 };
 
 /**
@@ -208,6 +222,9 @@ struct regulator_desc {
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
  * @regmap: regmap to use for core regmap helpers
+ * @ena_gpio: GPIO controlling regulator enable.
+ * @ena_gpio_invert: Sense for GPIO enable control.
+ * @ena_gpio_flags: Flags to use when calling gpio_request_one()
  */
 struct regulator_config {
        struct device *dev;
@@ -215,6 +232,10 @@ struct regulator_config {
        void *driver_data;
        struct device_node *of_node;
        struct regmap *regmap;
+
+       int ena_gpio;
+       unsigned int ena_gpio_invert:1;
+       unsigned int ena_gpio_flags;
 };
 
 /*
@@ -253,6 +274,10 @@ struct regulator_dev {
        void *reg_data;         /* regulator_dev data */
 
        struct dentry *debugfs;
+
+       int ena_gpio;
+       unsigned int ena_gpio_invert:1;
+       unsigned int ena_gpio_state:1;
 };
 
 struct regulator_dev *
@@ -271,6 +296,8 @@ int regulator_mode_to_status(unsigned int);
 
 int regulator_list_voltage_linear(struct regulator_dev *rdev,
                                  unsigned int selector);
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+                                 unsigned int selector);
 int regulator_map_voltage_linear(struct regulator_dev *rdev,
                                  int min_uV, int max_uV);
 int regulator_map_voltage_iterate(struct regulator_dev *rdev,
@@ -280,6 +307,9 @@ int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
 int regulator_is_enabled_regmap(struct regulator_dev *rdev);
 int regulator_enable_regmap(struct regulator_dev *rdev);
 int regulator_disable_regmap(struct regulator_dev *rdev);
+int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+                                  unsigned int old_selector,
+                                  unsigned int new_selector);
 
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 
index f83f7440b4885656f171f904e8a1a150141cef36..48918be649d499b55bfaf762b23d9d7ae0df201e 100644 (file)
@@ -22,6 +22,7 @@ struct regulator_init_data;
 /**
  * struct fixed_voltage_config - fixed_voltage_config structure
  * @supply_name:       Name of the regulator supply
+ * @input_supply:      Name of the input regulator supply
  * @microvolts:                Output voltage of regulator
  * @gpio:              GPIO to use for enable control
  *                     set to -EINVAL if not used
@@ -46,6 +47,7 @@ struct regulator_init_data;
  */
 struct fixed_voltage_config {
        const char *supply_name;
+       const char *input_supply;
        int microvolts;
        int gpio;
        unsigned startup_delay;
@@ -58,14 +60,17 @@ struct fixed_voltage_config {
 struct regulator_consumer_supply;
 
 #if IS_ENABLED(CONFIG_REGULATOR)
-struct platform_device *regulator_register_fixed(int id,
-               struct regulator_consumer_supply *supplies, int num_supplies);
+struct platform_device *regulator_register_always_on(int id, const char *name,
+               struct regulator_consumer_supply *supplies, int num_supplies, int uv);
 #else
-static inline struct platform_device *regulator_register_fixed(int id,
-               struct regulator_consumer_supply *supplies, int num_supplies)
+static inline struct platform_device *regulator_register_always_on(int id, const char *name,
+               struct regulator_consumer_supply *supplies, int num_supplies, int uv)
 {
        return NULL;
 }
 #endif
 
+#define regulator_register_fixed(id, s, ns) regulator_register_always_on(id, \
+                                               "fixed-dummy", s, ns, 0)
+
 #endif
diff --git a/include/linux/regulator/lp872x.h b/include/linux/regulator/lp872x.h
new file mode 100644 (file)
index 0000000..132e05c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LP872X_REGULATOR_H__
+#define __LP872X_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#define LP872X_MAX_REGULATORS          9
+
+enum lp872x_regulator_id {
+       LP8720_ID_BASE,
+       LP8720_ID_LDO1 = LP8720_ID_BASE,
+       LP8720_ID_LDO2,
+       LP8720_ID_LDO3,
+       LP8720_ID_LDO4,
+       LP8720_ID_LDO5,
+       LP8720_ID_BUCK,
+
+       LP8725_ID_BASE,
+       LP8725_ID_LDO1 = LP8725_ID_BASE,
+       LP8725_ID_LDO2,
+       LP8725_ID_LDO3,
+       LP8725_ID_LDO4,
+       LP8725_ID_LDO5,
+       LP8725_ID_LILO1,
+       LP8725_ID_LILO2,
+       LP8725_ID_BUCK1,
+       LP8725_ID_BUCK2,
+
+       LP872X_ID_MAX,
+};
+
+enum lp872x_dvs_state {
+       DVS_LOW  = GPIOF_OUT_INIT_LOW,
+       DVS_HIGH = GPIOF_OUT_INIT_HIGH,
+};
+
+enum lp872x_dvs_sel {
+       SEL_V1,
+       SEL_V2,
+};
+
+/**
+ * lp872x_dvs
+ * @gpio       : gpio pin number for dvs control
+ * @vsel       : dvs selector for buck v1 or buck v2 register
+ * @init_state : initial dvs pin state
+ */
+struct lp872x_dvs {
+       int gpio;
+       enum lp872x_dvs_sel vsel;
+       enum lp872x_dvs_state init_state;
+};
+
+/**
+ * lp872x_regdata
+ * @id        : regulator id
+ * @init_data : init data for each regulator
+ */
+struct lp872x_regulator_data {
+       enum lp872x_regulator_id id;
+       struct regulator_init_data *init_data;
+};
+
+/**
+ * lp872x_platform_data
+ * @general_config    : the value of LP872X_GENERAL_CFG register
+ * @update_config     : if LP872X_GENERAL_CFG register is updated, set true
+ * @regulator_data    : platform regulator id and init data
+ * @dvs               : dvs data for buck voltage control
+ */
+struct lp872x_platform_data {
+       u8 general_config;
+       bool update_config;
+       struct lp872x_regulator_data regulator_data[LP872X_MAX_REGULATORS];
+       struct lp872x_dvs *dvs;
+};
+
+#endif
index b02108446be756cc1c216271e21ac3cbf7a132d8..40dd0a394cfa95c1f470e0c2bbc6ee334005bef9 100644 (file)
@@ -92,6 +92,7 @@ struct regulator_state {
  *                 mode.
  * @initial_state: Suspend state to set by default.
  * @initial_mode: Mode to set at startup.
+ * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
  */
 struct regulation_constraints {
 
@@ -125,6 +126,8 @@ struct regulation_constraints {
        /* mode to set on startup */
        unsigned int initial_mode;
 
+       unsigned int ramp_delay;
+
        /* constraint flags */
        unsigned always_on:1;   /* regulator never off when system is on */
        unsigned boot_on:1;     /* bootloader/firmware enabled regulator */
index a8e50e44203c868d1957ba6170e9074569f0235e..82a673905edb12ee0ad6e466423439a31b407c49 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/types.h>
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
 
 /* The feature bitmap for virtio rpmsg */
 #define VIRTIO_RPMSG_F_NS      0 /* RP supports name service notifications */
@@ -120,7 +122,9 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
 /**
  * struct rpmsg_endpoint - binds a local rpmsg address to its user
  * @rpdev: rpmsg channel device
+ * @refcount: when this drops to zero, the ept is deallocated
  * @cb: rx callback handler
+ * @cb_lock: must be taken before accessing/changing @cb
  * @addr: local rpmsg address
  * @priv: private data for the driver's use
  *
@@ -140,7 +144,9 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
  */
 struct rpmsg_endpoint {
        struct rpmsg_channel *rpdev;
+       struct kref refcount;
        rpmsg_rx_cb_t cb;
+       struct mutex cb_lock;
        u32 addr;
        void *priv;
 };
index 4059c0f33f07a7454d545753281898d92e2d657f..1a2ebd39b8006b9021faf9b51ca18a0504dee85b 100644 (file)
@@ -1405,7 +1405,7 @@ struct task_struct {
        int (*notifier)(void *priv);
        void *notifier_data;
        sigset_t *notifier_mask;
-       struct hlist_head task_works;
+       struct callback_head *task_works;
 
        struct audit_context *audit_context;
 #ifdef CONFIG_AUDITSYSCALL
@@ -1546,7 +1546,6 @@ struct task_struct {
        unsigned long timer_slack_ns;
        unsigned long default_timer_slack_ns;
 
-       struct list_head        *scm_work_list;
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        /* Index of current stored address in ret_stack */
        int curr_ret_stack;
@@ -1581,7 +1580,6 @@ struct task_struct {
 #endif
 #ifdef CONFIG_UPROBES
        struct uprobe_task *utask;
-       int uprobe_srcu_id;
 #endif
 };
 
@@ -1871,22 +1869,12 @@ static inline void rcu_copy_process(struct task_struct *p)
        INIT_LIST_HEAD(&p->rcu_node_entry);
 }
 
-static inline void rcu_switch_from(struct task_struct *prev)
-{
-       if (prev->rcu_read_lock_nesting != 0)
-               rcu_preempt_note_context_switch();
-}
-
 #else
 
 static inline void rcu_copy_process(struct task_struct *p)
 {
 }
 
-static inline void rcu_switch_from(struct task_struct *prev)
-{
-}
-
 #endif
 
 #ifdef CONFIG_SMP
@@ -1909,6 +1897,14 @@ static inline int set_cpus_allowed_ptr(struct task_struct *p,
 }
 #endif
 
+#ifdef CONFIG_NO_HZ
+void calc_load_enter_idle(void);
+void calc_load_exit_idle(void);
+#else
+static inline void calc_load_enter_idle(void) { }
+static inline void calc_load_exit_idle(void) { }
+#endif /* CONFIG_NO_HZ */
+
 #ifndef CONFIG_CPUMASK_OFFSTACK
 static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
 {
index 717fb746c9a822ce1098870b17b706c184cfdeb7..dd6f06be3c9feb18ddc0a3752aaa43797c38fd08 100644 (file)
@@ -90,10 +90,6 @@ void kick_all_cpus_sync(void);
 void __init call_function_init(void);
 void generic_smp_call_function_single_interrupt(void);
 void generic_smp_call_function_interrupt(void);
-void ipi_call_lock(void);
-void ipi_call_unlock(void);
-void ipi_call_lock_irq(void);
-void ipi_call_unlock_irq(void);
 #else
 static inline void call_function_init(void) { }
 #endif
@@ -181,7 +177,6 @@ static inline int up_smp_call_function(smp_call_func_t func, void *info)
        } while (0)
 
 static inline void smp_send_reschedule(int cpu) { }
-#define num_booting_cpus()                     1
 #define smp_prepare_boot_cpu()                 do {} while (0)
 #define smp_call_function_many(mask, func, info, wait) \
                        (up_smp_call_function(func, info))
index 26e5b613deda9e63816b58c59f53f06d7dccd50c..09a545a7dfa39bcd7f736f446358d4c3b112aae4 100644 (file)
@@ -51,7 +51,8 @@ struct partial_page {
 struct splice_pipe_desc {
        struct page **pages;            /* page map */
        struct partial_page *partial;   /* pages[] may not be contig */
-       int nr_pages;                   /* number of pages in map */
+       int nr_pages;                   /* number of populated pages in map */
+       unsigned int nr_pages_max;      /* pages[] & partial[] arrays size */
        unsigned int flags;             /* splice flags */
        const struct pipe_buf_operations *ops;/* ops associated with output pipe */
        void (*spd_release)(struct splice_pipe_desc *, unsigned int);
@@ -85,9 +86,8 @@ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
 /*
  * for dynamic pipe sizing
  */
-extern int splice_grow_spd(struct pipe_inode_info *, struct splice_pipe_desc *);
-extern void splice_shrink_spd(struct pipe_inode_info *,
-                               struct splice_pipe_desc *);
+extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *);
+extern void splice_shrink_spd(struct splice_pipe_desc *);
 extern void spd_release_page(struct splice_pipe_desc *, unsigned int);
 
 extern const struct pipe_buf_operations page_cache_pipe_buf_ops;
index cd83059fb592c7464fc2e812d92e315fe7c77381..0c808d7fa579ec81d2da272caa0cc6630c9635a2 100644 (file)
@@ -408,6 +408,12 @@ static inline void unlock_system_sleep(void) {}
 
 #endif /* !CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_PM_SLEEP_DEBUG
+extern bool pm_print_times_enabled;
+#else
+#define pm_print_times_enabled (false)
+#endif
+
 #ifdef CONFIG_PM_AUTOSLEEP
 
 /* kernel/power/autosleep.c */
index 294d5d5e90b1fe410da2330f0bd0dfce132a021d..fb46b03b18522752538bfae6e192804e9629fc2a 100644 (file)
@@ -4,29 +4,21 @@
 #include <linux/list.h>
 #include <linux/sched.h>
 
-struct task_work;
-typedef void (*task_work_func_t)(struct task_work *);
-
-struct task_work {
-       struct hlist_node hlist;
-       task_work_func_t func;
-       void *data;
-};
+typedef void (*task_work_func_t)(struct callback_head *);
 
 static inline void
-init_task_work(struct task_work *twork, task_work_func_t func, void *data)
+init_task_work(struct callback_head *twork, task_work_func_t func)
 {
        twork->func = func;
-       twork->data = data;
 }
 
-int task_work_add(struct task_struct *task, struct task_work *twork, bool);
-struct task_work *task_work_cancel(struct task_struct *, task_work_func_t);
+int task_work_add(struct task_struct *task, struct callback_head *twork, bool);
+struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t);
 void task_work_run(void);
 
 static inline void exit_task_work(struct task_struct *task)
 {
-       if (unlikely(!hlist_empty(&task->task_works)))
+       if (unlikely(task->task_works))
                task_work_run();
 }
 
index ab8be90b5cc957c9fad62cab8c86796a0645d77a..f37fceb69b73d294e9b045293f6bbbf71b72388d 100644 (file)
@@ -31,10 +31,10 @@ enum tick_nohz_mode {
  * struct tick_sched - sched tick emulation and no idle tick control/stats
  * @sched_timer:       hrtimer to schedule the periodic tick in high
  *                     resolution mode
- * @idle_tick:         Store the last idle tick expiry time when the tick
- *                     timer is modified for idle sleeps. This is necessary
+ * @last_tick:         Store the last tick expiry time when the tick
+ *                     timer is modified for nohz sleeps. This is necessary
  *                     to resume the tick timer operation in the timeline
- *                     when the CPU returns from idle
+ *                     when the CPU returns from nohz sleep.
  * @tick_stopped:      Indicator that the idle tick has been stopped
  * @idle_jiffies:      jiffies at the entry to idle for idle time accounting
  * @idle_calls:                Total number of idle calls
@@ -51,7 +51,7 @@ struct tick_sched {
        struct hrtimer                  sched_timer;
        unsigned long                   check_clocks;
        enum tick_nohz_mode             nohz_mode;
-       ktime_t                         idle_tick;
+       ktime_t                         last_tick;
        int                             inidle;
        int                             tick_stopped;
        unsigned long                   idle_jiffies;
index 6a4d82bedb03d4f6e9742069c40324c0441265f0..1e98b553042598e0d1d6a41337bec8194ee54a63 100644 (file)
@@ -192,7 +192,7 @@ static inline void tracehook_notify_resume(struct pt_regs *regs)
         * hlist_add_head(task->task_works);
         */
        smp_mb__after_clear_bit();
-       if (unlikely(!hlist_empty(&current->task_works)))
+       if (unlikely(current->task_works))
                task_work_run();
 }
 
index bd96ecd0e05c731c7b55306b693fec2f81cc3d06..802de56c41e8660bd87defec22fdbd6c4d1eb857 100644 (file)
@@ -153,7 +153,7 @@ static inline void tracepoint_synchronize_unregister(void)
        }                                                               \
        static inline void trace_##name##_rcuidle(proto)                \
        {                                                               \
-               if (static_branch(&__tracepoint_##name.key))            \
+               if (static_key_false(&__tracepoint_##name.key))         \
                        __DO_TRACE(&__tracepoint_##name,                \
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args),                     \
index 9c1bd539ea70e780e0e926b54bfc9320d3ec34a4..bf0dd7524b2a81cb660723c08ce76857991df54e 100644 (file)
@@ -246,14 +246,15 @@ struct ustat {
 };
 
 /**
- * struct rcu_head - callback structure for use with RCU
+ * struct callback_head - callback structure for use with RCU and task_work
  * @next: next update requests in a list
  * @func: actual update function to call after the grace period.
  */
-struct rcu_head {
-       struct rcu_head *next;
-       void (*func)(struct rcu_head *head);
+struct callback_head {
+       struct callback_head *next;
+       void (*func)(struct callback_head *head);
 };
+#define rcu_head callback_head
 
 #endif /* __KERNEL__ */
 #endif /*  __ASSEMBLY__ */
index d6146b4811c212601a365eee7c9c28789b76481a..95374d1696a163a75f8aa006bf99fe958df195aa 100644 (file)
@@ -1425,7 +1425,7 @@ static inline void ip_vs_notrack(struct sk_buff *skb)
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 
        if (!ct || !nf_ct_is_untracked(ct)) {
-               nf_reset(skb);
+               nf_conntrack_put(skb->nfct);
                skb->nfct = &nf_ct_untracked_get()->ct_general;
                skb->nfctinfo = IP_CT_NEW;
                nf_conntrack_get(skb->nfct);
index a88fb6939387f228ac5826949f68151e0fceaf16..e1ce1048fe5fa1142196cb88e08829b7bb1d60f5 100644 (file)
@@ -78,7 +78,7 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
        struct net *net = nf_ct_net(ct);
        struct nf_conntrack_ecache *e;
 
-       if (net->ct.nf_conntrack_event_cb == NULL)
+       if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
                return;
 
        e = nf_ct_ecache_find(ct);
index d456f4c71a323b18b4bcbf24ca59a5bc96b8243a..079d7887dac13697d0dfc5d0cc6ce256800151d0 100644 (file)
@@ -13,7 +13,6 @@
 #define SCM_MAX_FD     253
 
 struct scm_fp_list {
-       struct list_head        list;
        short                   count;
        short                   max;
        struct file             *fp[SCM_MAX_FD];
index e4652fe5895863d956a52e436d10f1fc3724415b..fecdf31816f2fc6a834a060cfdd39158dcb30bc2 100644 (file)
@@ -912,6 +912,9 @@ struct sctp_transport {
                /* Is this structure kfree()able? */
                malloced:1;
 
+       /* Has this transport moved the ctsn since we last sacked */
+       __u32 sack_generation;
+
        struct flowi fl;
 
        /* This is the peer's IP address and port. */
@@ -1584,6 +1587,7 @@ struct sctp_association {
                 */
                __u8    sack_needed;     /* Do we need to sack the peer? */
                __u32   sack_cnt;
+               __u32   sack_generation;
 
                /* These are capabilities which our peer advertised.  */
                __u8    ecn_capable:1,      /* Can peer do ECN? */
index e7728bc14ccfde5bd85c3b08f990487af66ab072..2c5d2b4d5d1eb51542df26094700250ab6191070 100644 (file)
@@ -117,7 +117,8 @@ void sctp_tsnmap_free(struct sctp_tsnmap *map);
 int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
+int sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn,
+                    struct sctp_transport *trans);
 
 /* Mark this TSN and all lower as seen. */
 void sctp_tsnmap_skip(struct sctp_tsnmap *map, __u32 tsn);
index f4f1c96dca726ff2f00211994dcf7381ef55b5b0..10ce74f589c5fd57622f630a17fbbc7e736d24e4 100644 (file)
@@ -163,6 +163,8 @@ enum ata_command_set {
         ATAPI_COMMAND_SET = 1,
 };
 
+#define ATA_RESP_FIS_SIZE 24
+
 struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
@@ -171,7 +173,7 @@ struct sata_device {
 
        struct ata_port *ap;
        struct ata_host ata_host;
-       struct ata_taskfile tf;
+       u8     fis[ATA_RESP_FIS_SIZE];
 };
 
 enum {
@@ -537,7 +539,7 @@ enum exec_status {
  */
 struct ata_task_resp {
        u16  frame_len;
-       u8   ending_fis[24];      /* dev to host or data-in */
+       u8   ending_fis[ATA_RESP_FIS_SIZE];       /* dev to host or data-in */
 };
 
 #define SAS_STATUS_BUF_SIZE 96
index 1e1198546c725d43a7ff6baa657c25ef364d73ee..ac06cc595890ef87a8e01632f5872ab11e4057f2 100644 (file)
@@ -134,10 +134,16 @@ struct scsi_cmnd {
 
 static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
 {
+       struct scsi_driver **sdp;
+
        if (!cmd->request->rq_disk)
                return NULL;
 
-       return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
+       sdp = (struct scsi_driver **)cmd->request->rq_disk->private_data;
+       if (!sdp)
+               return NULL;
+
+       return *sdp;
 }
 
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
index 2d7db85e93ae8a7fa8406a1bde8ebc91afa99ff2..f1405d335a968d093aadafee06ab4be105970f88 100644 (file)
@@ -24,10 +24,8 @@ struct se_subsystem_api {
                                struct se_subsystem_dev *, void *);
        void (*free_device)(void *);
        int (*transport_complete)(struct se_cmd *cmd, struct scatterlist *);
-       int (*execute_cmd)(struct se_cmd *, struct scatterlist *, u32,
-                       enum dma_data_direction);
-       int (*do_discard)(struct se_device *, sector_t, u32);
-       void (*do_sync_cache)(struct se_cmd *);
+
+       int (*parse_cdb)(struct se_cmd *cmd);
        ssize_t (*check_configfs_dev_params)(struct se_hba *,
                        struct se_subsystem_dev *);
        ssize_t (*set_configfs_dev_params)(struct se_hba *,
@@ -40,6 +38,13 @@ struct se_subsystem_api {
        unsigned char *(*get_sense_buffer)(struct se_cmd *);
 };
 
+struct spc_ops {
+       int (*execute_rw)(struct se_cmd *cmd);
+       int (*execute_sync_cache)(struct se_cmd *cmd);
+       int (*execute_write_same)(struct se_cmd *cmd);
+       int (*execute_unmap)(struct se_cmd *cmd);
+};
+
 int    transport_subsystem_register(struct se_subsystem_api *);
 void   transport_subsystem_release(struct se_subsystem_api *);
 
@@ -49,6 +54,10 @@ struct se_device *transport_add_device_to_core_hba(struct se_hba *,
 
 void   target_complete_cmd(struct se_cmd *, u8);
 
+int    sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops);
+int    spc_parse_cdb(struct se_cmd *cmd, unsigned int *size);
+int    spc_get_write_same_sectors(struct se_cmd *cmd);
+
 void   transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
 int    transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
 int    transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *);
index dc35d8660aa68ba44f43a684f136e548bc54424f..128ce46fa48a799fa9b3b332a07d2babfee01925 100644 (file)
@@ -145,12 +145,9 @@ enum transport_state_table {
        TRANSPORT_NO_STATE      = 0,
        TRANSPORT_NEW_CMD       = 1,
        TRANSPORT_WRITE_PENDING = 3,
-       TRANSPORT_PROCESS_WRITE = 4,
        TRANSPORT_PROCESSING    = 5,
        TRANSPORT_COMPLETE      = 6,
-       TRANSPORT_PROCESS_TMR   = 9,
        TRANSPORT_ISTATE_PROCESSING = 11,
-       TRANSPORT_NEW_CMD_MAP   = 16,
        TRANSPORT_COMPLETE_QF_WP = 18,
        TRANSPORT_COMPLETE_QF_OK = 19,
 };
@@ -160,25 +157,20 @@ enum se_cmd_flags_table {
        SCF_SUPPORTED_SAM_OPCODE        = 0x00000001,
        SCF_TRANSPORT_TASK_SENSE        = 0x00000002,
        SCF_EMULATED_TASK_SENSE         = 0x00000004,
-       SCF_SCSI_DATA_SG_IO_CDB         = 0x00000008,
-       SCF_SCSI_CONTROL_SG_IO_CDB      = 0x00000010,
-       SCF_SCSI_NON_DATA_CDB           = 0x00000020,
-       SCF_SCSI_TMR_CDB                = 0x00000040,
-       SCF_SCSI_CDB_EXCEPTION          = 0x00000080,
-       SCF_SCSI_RESERVATION_CONFLICT   = 0x00000100,
-       SCF_FUA                         = 0x00000200,
-       SCF_SE_LUN_CMD                  = 0x00000800,
-       SCF_SE_ALLOW_EOO                = 0x00001000,
-       SCF_BIDI                        = 0x00002000,
-       SCF_SENT_CHECK_CONDITION        = 0x00004000,
-       SCF_OVERFLOW_BIT                = 0x00008000,
-       SCF_UNDERFLOW_BIT               = 0x00010000,
-       SCF_SENT_DELAYED_TAS            = 0x00020000,
-       SCF_ALUA_NON_OPTIMIZED          = 0x00040000,
-       SCF_DELAYED_CMD_FROM_SAM_ATTR   = 0x00080000,
-       SCF_UNUSED                      = 0x00100000,
-       SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00200000,
-       SCF_ACK_KREF                    = 0x00400000,
+       SCF_SCSI_DATA_CDB               = 0x00000008,
+       SCF_SCSI_TMR_CDB                = 0x00000010,
+       SCF_SCSI_CDB_EXCEPTION          = 0x00000020,
+       SCF_SCSI_RESERVATION_CONFLICT   = 0x00000040,
+       SCF_FUA                         = 0x00000080,
+       SCF_SE_LUN_CMD                  = 0x00000100,
+       SCF_BIDI                        = 0x00000400,
+       SCF_SENT_CHECK_CONDITION        = 0x00000800,
+       SCF_OVERFLOW_BIT                = 0x00001000,
+       SCF_UNDERFLOW_BIT               = 0x00002000,
+       SCF_SENT_DELAYED_TAS            = 0x00004000,
+       SCF_ALUA_NON_OPTIMIZED          = 0x00008000,
+       SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
+       SCF_ACK_KREF                    = 0x00040000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -220,6 +212,7 @@ enum tcm_sense_reason_table {
        TCM_CHECK_CONDITION_UNIT_ATTENTION      = 0x0e,
        TCM_CHECK_CONDITION_NOT_READY           = 0x0f,
        TCM_RESERVATION_CONFLICT                = 0x10,
+       TCM_ADDRESS_OUT_OF_RANGE                = 0x11,
 };
 
 enum target_sc_flags_table {
@@ -471,13 +464,6 @@ struct t10_reservation {
        struct t10_reservation_ops pr_ops;
 };
 
-struct se_queue_obj {
-       atomic_t                queue_cnt;
-       spinlock_t              cmd_queue_lock;
-       struct list_head        qobj_list;
-       wait_queue_head_t       thread_wq;
-};
-
 struct se_tmr_req {
        /* Task Management function to be performed */
        u8                      function;
@@ -486,11 +472,8 @@ struct se_tmr_req {
        int                     call_transport;
        /* Reference to ITT that Task Mgmt should be performed */
        u32                     ref_task_tag;
-       /* 64-bit encoded SAM LUN from $FABRIC_MOD TMR header */
-       u64                     ref_task_lun;
        void                    *fabric_tmr_ptr;
        struct se_cmd           *task_cmd;
-       struct se_cmd           *ref_cmd;
        struct se_device        *tmr_dev;
        struct se_lun           *tmr_lun;
        struct list_head        tmr_list;
@@ -537,7 +520,6 @@ struct se_cmd {
        /* Only used for internal passthrough and legacy TCM fabric modules */
        struct se_session       *se_sess;
        struct se_tmr_req       *se_tmr_req;
-       struct list_head        se_queue_node;
        struct list_head        se_cmd_list;
        struct completion       cmd_wait_comp;
        struct kref             cmd_kref;
@@ -575,7 +557,6 @@ struct se_cmd {
        struct scatterlist      *t_bidi_data_sg;
        unsigned int            t_bidi_data_nents;
 
-       struct list_head        execute_list;
        struct list_head        state_list;
        bool                    state_active;
 
@@ -633,7 +614,6 @@ struct se_session {
        struct list_head        sess_list;
        struct list_head        sess_acl_list;
        struct list_head        sess_cmd_list;
-       struct list_head        sess_wait_list;
        spinlock_t              sess_cmd_lock;
        struct kref             sess_kref;
 };
@@ -780,13 +760,11 @@ struct se_device {
        /* Active commands on this virtual SE device */
        atomic_t                simple_cmds;
        atomic_t                dev_ordered_id;
-       atomic_t                execute_tasks;
        atomic_t                dev_ordered_sync;
        atomic_t                dev_qf_count;
        struct se_obj           dev_obj;
        struct se_obj           dev_access_obj;
        struct se_obj           dev_export_obj;
-       struct se_queue_obj     dev_queue_obj;
        spinlock_t              delayed_cmd_lock;
        spinlock_t              execute_task_lock;
        spinlock_t              dev_reservation_lock;
@@ -802,11 +780,9 @@ struct se_device {
        struct t10_pr_registration *dev_pr_res_holder;
        struct list_head        dev_sep_list;
        struct list_head        dev_tmr_list;
-       /* Pointer to descriptor for processing thread */
-       struct task_struct      *process_thread;
+       struct workqueue_struct *tmr_wq;
        struct work_struct      qf_work_queue;
        struct list_head        delayed_cmd_list;
-       struct list_head        execute_list;
        struct list_head        state_list;
        struct list_head        qf_cmd_list;
        /* Pointer to associated SE HBA */
index c78a23333c4fb801c72e86a55b05fd7e7bf66f67..69fb3cfd02d7f2acc0d656b458287d4d89666f82 100644 (file)
@@ -32,12 +32,6 @@ struct target_core_fabric_ops {
        void (*tpg_release_fabric_acl)(struct se_portal_group *,
                                        struct se_node_acl *);
        u32 (*tpg_get_inst_index)(struct se_portal_group *);
-       /*
-        * Optional function pointer for TCM to perform command map
-        * from TCM processing thread context, for those struct se_cmd
-        * initially allocated in interrupt context.
-        */
-       int (*new_cmd_map)(struct se_cmd *);
        /*
         * Optional to release struct se_cmd and fabric dependent allocated
         * I/O descriptor in transport_cmd_check_stop().
@@ -108,20 +102,18 @@ void      transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
                struct se_session *, u32, int, int, unsigned char *);
 int    transport_lookup_cmd_lun(struct se_cmd *, u32);
 int    target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
-void   target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
+int    target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
                unsigned char *, u32, u32, int, int, int);
 int    target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
                unsigned char *sense, u32 unpacked_lun,
                void *fabric_tmr_ptr, unsigned char tm_type,
                gfp_t, unsigned int, int);
 int    transport_handle_cdb_direct(struct se_cmd *);
-int    transport_generic_handle_cdb_map(struct se_cmd *);
-int    transport_generic_handle_data(struct se_cmd *);
 int    transport_generic_map_mem_to_cmd(struct se_cmd *cmd,
                struct scatterlist *, u32, struct scatterlist *, u32);
 int    transport_generic_new_cmd(struct se_cmd *);
 
-void   transport_generic_process_write(struct se_cmd *);
+void   target_execute_cmd(struct se_cmd *cmd);
 
 void   transport_generic_free_cmd(struct se_cmd *, int);
 
@@ -129,9 +121,8 @@ bool        transport_wait_for_tasks(struct se_cmd *);
 int    transport_check_aborted_status(struct se_cmd *, int);
 int    transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
 
-void   target_get_sess_cmd(struct se_session *, struct se_cmd *, bool);
 int    target_put_sess_cmd(struct se_session *, struct se_cmd *);
-void   target_splice_sess_cmd_list(struct se_session *);
+void   target_sess_cmd_list_set_waiting(struct se_session *);
 void   target_wait_for_sess_cmds(struct se_session *, int);
 
 int    core_alua_check_nonop_delay(struct se_cmd *);
index d274734b2aa42fee56d7ce7ab2b7898d39521e7e..5bde94d8585b77c71e957926ed9ca7b5b85bcc5c 100644 (file)
@@ -541,6 +541,50 @@ TRACE_EVENT(rcu_torture_read,
                  __entry->rcutorturename, __entry->rhp)
 );
 
+/*
+ * Tracepoint for _rcu_barrier() execution.  The string "s" describes
+ * the _rcu_barrier phase:
+ *     "Begin": rcu_barrier_callback() started.
+ *     "Check": rcu_barrier_callback() checking for piggybacking.
+ *     "EarlyExit": rcu_barrier_callback() piggybacked, thus early exit.
+ *     "Inc1": rcu_barrier_callback() piggyback check counter incremented.
+ *     "Offline": rcu_barrier_callback() found offline CPU
+ *     "OnlineQ": rcu_barrier_callback() found online CPU with callbacks.
+ *     "OnlineNQ": rcu_barrier_callback() found online CPU, no callbacks.
+ *     "IRQ": An rcu_barrier_callback() callback posted on remote CPU.
+ *     "CB": An rcu_barrier_callback() invoked a callback, not the last.
+ *     "LastCB": An rcu_barrier_callback() invoked the last callback.
+ *     "Inc2": rcu_barrier_callback() piggyback check counter incremented.
+ * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument
+ * is the count of remaining callbacks, and "done" is the piggybacking count.
+ */
+TRACE_EVENT(rcu_barrier,
+
+       TP_PROTO(char *rcuname, char *s, int cpu, int cnt, unsigned long done),
+
+       TP_ARGS(rcuname, s, cpu, cnt, done),
+
+       TP_STRUCT__entry(
+               __field(char *, rcuname)
+               __field(char *, s)
+               __field(int, cpu)
+               __field(int, cnt)
+               __field(unsigned long, done)
+       ),
+
+       TP_fast_assign(
+               __entry->rcuname = rcuname;
+               __entry->s = s;
+               __entry->cpu = cpu;
+               __entry->cnt = cnt;
+               __entry->done = done;
+       ),
+
+       TP_printk("%s %s cpu %d remaining %d # %lu",
+                 __entry->rcuname, __entry->s, __entry->cpu, __entry->cnt,
+                 __entry->done)
+);
+
 #else /* #ifdef CONFIG_RCU_TRACE */
 
 #define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0)
@@ -564,6 +608,7 @@ TRACE_EVENT(rcu_torture_read,
 #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \
        do { } while (0)
 #define trace_rcu_torture_read(rcutorturename, rhp) do { } while (0)
+#define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0)
 
 #endif /* #else #ifdef CONFIG_RCU_TRACE */
 
index 769724944fc60ccbbb2fcab4d03a6fe832fe679e..c6bc2faaf2611533b1b2a72e6d3e191fa6033616 100644 (file)
@@ -571,6 +571,7 @@ static inline void ftrace_test_probe_##call(void)                   \
 
 #undef __print_flags
 #undef __print_symbolic
+#undef __print_hex
 #undef __get_dynamic_array
 #undef __get_str
 
index b5cc0a7c4708f167925aa1f974eb356f99de1ebc..3f151f6c6da79cd2e28d55ba513aed39b2593923 100644 (file)
@@ -68,6 +68,7 @@
 #include <linux/shmem_fs.h>
 #include <linux/slab.h>
 #include <linux/perf_event.h>
+#include <linux/file.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -804,8 +805,8 @@ static noinline int init_post(void)
        system_state = SYSTEM_RUNNING;
        numa_default_policy();
 
-
        current->signal->flags |= SIGNAL_UNKILLABLE;
+       flush_delayed_fput();
 
        if (ramdisk_execute_command) {
                run_init_process(ramdisk_execute_command);
index 8ce57691e7b60994d9cc97620b7550c603df5391..f8e54f5b90804ea58309da551fcd40dd8cf12333 100644 (file)
@@ -413,7 +413,7 @@ static void mqueue_evict_inode(struct inode *inode)
 }
 
 static int mqueue_create(struct inode *dir, struct dentry *dentry,
-                               umode_t mode, struct nameidata *nd)
+                               umode_t mode, bool excl)
 {
        struct inode *inode;
        struct mq_attr *attr = dentry->d_fsdata;
@@ -721,8 +721,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
 /*
  * Invoked when creating a new queue via sys_mq_open
  */
-static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
-                       struct dentry *dentry, int oflag, umode_t mode,
+static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
+                       struct path *path, int oflag, umode_t mode,
                        struct mq_attr *attr)
 {
        const struct cred *cred = current_cred();
@@ -732,9 +732,9 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
        if (attr) {
                ret = mq_attr_ok(ipc_ns, attr);
                if (ret)
-                       goto out;
+                       return ERR_PTR(ret);
                /* store for use during create */
-               dentry->d_fsdata = attr;
+               path->dentry->d_fsdata = attr;
        } else {
                struct mq_attr def_attr;
 
@@ -744,71 +744,51 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
                                          ipc_ns->mq_msgsize_default);
                ret = mq_attr_ok(ipc_ns, &def_attr);
                if (ret)
-                       goto out;
+                       return ERR_PTR(ret);
        }
 
        mode &= ~current_umask();
-       ret = mnt_want_write(ipc_ns->mq_mnt);
+       ret = mnt_want_write(path->mnt);
        if (ret)
-               goto out;
-       ret = vfs_create(dir->d_inode, dentry, mode, NULL);
-       dentry->d_fsdata = NULL;
-       if (ret)
-               goto out_drop_write;
-
-       result = dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
+               return ERR_PTR(ret);
+       ret = vfs_create(dir, path->dentry, mode, true);
+       path->dentry->d_fsdata = NULL;
+       if (!ret)
+               result = dentry_open(path, oflag, cred);
+       else
+               result = ERR_PTR(ret);
        /*
         * dentry_open() took a persistent mnt_want_write(),
         * so we can now drop this one.
         */
-       mnt_drop_write(ipc_ns->mq_mnt);
+       mnt_drop_write(path->mnt);
        return result;
-
-out_drop_write:
-       mnt_drop_write(ipc_ns->mq_mnt);
-out:
-       dput(dentry);
-       mntput(ipc_ns->mq_mnt);
-       return ERR_PTR(ret);
 }
 
 /* Opens existing queue */
-static struct file *do_open(struct ipc_namespace *ipc_ns,
-                               struct dentry *dentry, int oflag)
+static struct file *do_open(struct path *path, int oflag)
 {
-       int ret;
-       const struct cred *cred = current_cred();
-
        static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
                                                  MAY_READ | MAY_WRITE };
-
-       if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
-               ret = -EINVAL;
-               goto err;
-       }
-
-       if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
-               ret = -EACCES;
-               goto err;
-       }
-
-       return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
-
-err:
-       dput(dentry);
-       mntput(ipc_ns->mq_mnt);
-       return ERR_PTR(ret);
+       int acc;
+       if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
+               return ERR_PTR(-EINVAL);
+       acc = oflag2acc[oflag & O_ACCMODE];
+       if (inode_permission(path->dentry->d_inode, acc))
+               return ERR_PTR(-EACCES);
+       return dentry_open(path, oflag, current_cred());
 }
 
 SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
                struct mq_attr __user *, u_attr)
 {
-       struct dentry *dentry;
+       struct path path;
        struct file *filp;
        char *name;
        struct mq_attr attr;
        int fd, error;
        struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
+       struct dentry *root = ipc_ns->mq_mnt->mnt_root;
 
        if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
                return -EFAULT;
@@ -822,52 +802,49 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
        if (fd < 0)
                goto out_putname;
 
-       mutex_lock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
-       dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
-       if (IS_ERR(dentry)) {
-               error = PTR_ERR(dentry);
+       error = 0;
+       mutex_lock(&root->d_inode->i_mutex);
+       path.dentry = lookup_one_len(name, root, strlen(name));
+       if (IS_ERR(path.dentry)) {
+               error = PTR_ERR(path.dentry);
                goto out_putfd;
        }
-       mntget(ipc_ns->mq_mnt);
+       path.mnt = mntget(ipc_ns->mq_mnt);
 
        if (oflag & O_CREAT) {
-               if (dentry->d_inode) {  /* entry already exists */
-                       audit_inode(name, dentry);
+               if (path.dentry->d_inode) {     /* entry already exists */
+                       audit_inode(name, path.dentry);
                        if (oflag & O_EXCL) {
                                error = -EEXIST;
                                goto out;
                        }
-                       filp = do_open(ipc_ns, dentry, oflag);
+                       filp = do_open(&path, oflag);
                } else {
-                       filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root,
-                                               dentry, oflag, mode,
+                       filp = do_create(ipc_ns, root->d_inode,
+                                               &path, oflag, mode,
                                                u_attr ? &attr : NULL);
                }
        } else {
-               if (!dentry->d_inode) {
+               if (!path.dentry->d_inode) {
                        error = -ENOENT;
                        goto out;
                }
-               audit_inode(name, dentry);
-               filp = do_open(ipc_ns, dentry, oflag);
+               audit_inode(name, path.dentry);
+               filp = do_open(&path, oflag);
        }
 
-       if (IS_ERR(filp)) {
+       if (!IS_ERR(filp))
+               fd_install(fd, filp);
+       else
                error = PTR_ERR(filp);
-               goto out_putfd;
-       }
-
-       fd_install(fd, filp);
-       goto out_upsem;
-
 out:
-       dput(dentry);
-       mntput(ipc_ns->mq_mnt);
+       path_put(&path);
 out_putfd:
-       put_unused_fd(fd);
-       fd = error;
-out_upsem:
-       mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
+       if (error) {
+               put_unused_fd(fd);
+               fd = error;
+       }
+       mutex_unlock(&root->d_inode->i_mutex);
 out_putname:
        putname(name);
        return fd;
index 5bf0790497e7779cf1001f6cb30c214de812ccd5..3a5ca582ba1ebe2373803bfbf1887357d05b523e 100644 (file)
@@ -595,7 +595,7 @@ void audit_trim_trees(void)
 
                root_mnt = collect_mounts(&path);
                path_put(&path);
-               if (!root_mnt)
+               if (IS_ERR(root_mnt))
                        goto skip_it;
 
                spin_lock(&hash_lock);
@@ -669,8 +669,8 @@ int audit_add_tree_rule(struct audit_krule *rule)
                goto Err;
        mnt = collect_mounts(&path);
        path_put(&path);
-       if (!mnt) {
-               err = -ENOMEM;
+       if (IS_ERR(mnt)) {
+               err = PTR_ERR(mnt);
                goto Err;
        }
 
@@ -719,8 +719,8 @@ int audit_tag_tree(char *old, char *new)
                return err;
        tagged = collect_mounts(&path2);
        path_put(&path2);
-       if (!tagged)
-               return -ENOMEM;
+       if (IS_ERR(tagged))
+               return PTR_ERR(tagged);
 
        err = kern_path(old, 0, &path1);
        if (err) {
index e683869365d9bdaf60abcb44e37da05506ab5672..3823281401b57e423f9a4ba9255b5904920e7e1d 100644 (file)
@@ -355,34 +355,15 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
 /* Get path information necessary for adding watches. */
 static int audit_get_nd(struct audit_watch *watch, struct path *parent)
 {
-       struct nameidata nd;
-       struct dentry *d;
-       int err;
-
-       err = kern_path_parent(watch->path, &nd);
-       if (err)
-               return err;
-
-       if (nd.last_type != LAST_NORM) {
-               path_put(&nd.path);
-               return -EINVAL;
-       }
-
-       mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-       d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
-       if (IS_ERR(d)) {
-               mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-               path_put(&nd.path);
+       struct dentry *d = kern_path_locked(watch->path, parent);
+       if (IS_ERR(d))
                return PTR_ERR(d);
-       }
+       mutex_unlock(&parent->dentry->d_inode->i_mutex);
        if (d->d_inode) {
                /* update watch filter fields */
                watch->dev = d->d_inode->i_sb->s_dev;
                watch->ino = d->d_inode->i_ino;
        }
-       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-
-       *parent = nd.path;
        dput(d);
        return 0;
 }
index 2097684cf19474aee676513af39de14035c4fce7..af2b5641fc8b094617aa812ac203ff49272ab979 100644 (file)
@@ -822,7 +822,7 @@ EXPORT_SYMBOL_GPL(cgroup_unlock);
  */
 
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
-static struct dentry *cgroup_lookup(struct inode *, struct dentry *, struct nameidata *);
+static struct dentry *cgroup_lookup(struct inode *, struct dentry *, unsigned int);
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
 static int cgroup_populate_dir(struct cgroup *cgrp);
 static const struct inode_operations cgroup_dir_inode_operations;
@@ -901,13 +901,10 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
                mutex_unlock(&cgroup_mutex);
 
                /*
-                * We want to drop the active superblock reference from the
-                * cgroup creation after all the dentry refs are gone -
-                * kill_sb gets mighty unhappy otherwise.  Mark
-                * dentry->d_fsdata with cgroup_diput() to tell
-                * cgroup_d_release() to call deactivate_super().
+                * Drop the active superblock reference that we took when we
+                * created the cgroup
                 */
-               dentry->d_fsdata = cgroup_diput;
+               deactivate_super(cgrp->root->sb);
 
                /*
                 * if we're getting rid of the cgroup, refcount should ensure
@@ -933,13 +930,6 @@ static int cgroup_delete(const struct dentry *d)
        return 1;
 }
 
-static void cgroup_d_release(struct dentry *dentry)
-{
-       /* did cgroup_diput() tell me to deactivate super? */
-       if (dentry->d_fsdata == cgroup_diput)
-               deactivate_super(dentry->d_sb);
-}
-
 static void remove_dir(struct dentry *d)
 {
        struct dentry *parent = dget(d->d_parent);
@@ -1547,7 +1537,6 @@ static int cgroup_get_rootdir(struct super_block *sb)
        static const struct dentry_operations cgroup_dops = {
                .d_iput = cgroup_diput,
                .d_delete = cgroup_delete,
-               .d_release = cgroup_d_release,
        };
 
        struct inode *inode =
@@ -1598,7 +1587,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        opts.new_root = new_root;
 
        /* Locate an existing or new sb for this hierarchy */
-       sb = sget(fs_type, cgroup_test_super, cgroup_set_super, &opts);
+       sb = sget(fs_type, cgroup_test_super, cgroup_set_super, 0, &opts);
        if (IS_ERR(sb)) {
                ret = PTR_ERR(sb);
                cgroup_drop_root(opts.new_root);
@@ -2581,7 +2570,7 @@ static const struct inode_operations cgroup_dir_inode_operations = {
        .rename = cgroup_rename,
 };
 
-static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 {
        if (dentry->d_name.len > NAME_MAX)
                return ERR_PTR(-ENAMETOOLONG);
@@ -3894,8 +3883,12 @@ static void css_dput_fn(struct work_struct *work)
 {
        struct cgroup_subsys_state *css =
                container_of(work, struct cgroup_subsys_state, dput_work);
+       struct dentry *dentry = css->cgroup->dentry;
+       struct super_block *sb = dentry->d_sb;
 
-       dput(css->cgroup->dentry);
+       atomic_inc(&sb->s_active);
+       dput(dentry);
+       deactivate_super(sb);
 }
 
 static void init_cgroup_css(struct cgroup_subsys_state *css,
index 67b847dfa2bb64b58d30db51460f22243142ee2d..1f91413edb87d0c9b77efc4e84c9b2f9729e9b8c 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/kmsg_dump.h>
 #include <linux/reboot.h>
 #include <linux/sched.h>
 #include <linux/sysrq.h>
@@ -2040,8 +2041,15 @@ static int kdb_env(int argc, const char **argv)
  */
 static int kdb_dmesg(int argc, const char **argv)
 {
-       char *syslog_data[4], *start, *end, c = '\0', *p;
-       int diag, logging, logsize, lines = 0, adjust = 0, n;
+       int diag;
+       int logging;
+       int lines = 0;
+       int adjust = 0;
+       int n = 0;
+       int skip = 0;
+       struct kmsg_dumper dumper = { .active = 1 };
+       size_t len;
+       char buf[201];
 
        if (argc > 2)
                return KDB_ARGCOUNT;
@@ -2064,22 +2072,10 @@ static int kdb_dmesg(int argc, const char **argv)
                kdb_set(2, setargs);
        }
 
-       /* syslog_data[0,1] physical start, end+1.  syslog_data[2,3]
-        * logical start, end+1. */
-       kdb_syslog_data(syslog_data);
-       if (syslog_data[2] == syslog_data[3])
-               return 0;
-       logsize = syslog_data[1] - syslog_data[0];
-       start = syslog_data[2];
-       end = syslog_data[3];
-#define KDB_WRAP(p) (((p - syslog_data[0]) % logsize) + syslog_data[0])
-       for (n = 0, p = start; p < end; ++p) {
-               c = *KDB_WRAP(p);
-               if (c == '\n')
-                       ++n;
-       }
-       if (c != '\n')
-               ++n;
+       kmsg_dump_rewind_nolock(&dumper);
+       while (kmsg_dump_get_line_nolock(&dumper, 1, NULL, 0, NULL))
+               n++;
+
        if (lines < 0) {
                if (adjust >= n)
                        kdb_printf("buffer only contains %d lines, nothing "
@@ -2087,21 +2083,11 @@ static int kdb_dmesg(int argc, const char **argv)
                else if (adjust - lines >= n)
                        kdb_printf("buffer only contains %d lines, last %d "
                                   "lines printed\n", n, n - adjust);
-               if (adjust) {
-                       for (; start < end && adjust; ++start) {
-                               if (*KDB_WRAP(start) == '\n')
-                                       --adjust;
-                       }
-                       if (start < end)
-                               ++start;
-               }
-               for (p = start; p < end && lines; ++p) {
-                       if (*KDB_WRAP(p) == '\n')
-                               ++lines;
-               }
-               end = p;
+               skip = adjust;
+               lines = abs(lines);
        } else if (lines > 0) {
-               int skip = n - (adjust + lines);
+               skip = n - lines - adjust;
+               lines = abs(lines);
                if (adjust >= n) {
                        kdb_printf("buffer only contains %d lines, "
                                   "nothing printed\n", n);
@@ -2112,35 +2098,24 @@ static int kdb_dmesg(int argc, const char **argv)
                        kdb_printf("buffer only contains %d lines, first "
                                   "%d lines printed\n", n, lines);
                }
-               for (; start < end && skip; ++start) {
-                       if (*KDB_WRAP(start) == '\n')
-                               --skip;
-               }
-               for (p = start; p < end && lines; ++p) {
-                       if (*KDB_WRAP(p) == '\n')
-                               --lines;
-               }
-               end = p;
+       } else {
+               lines = n;
        }
-       /* Do a line at a time (max 200 chars) to reduce protocol overhead */
-       c = '\n';
-       while (start != end) {
-               char buf[201];
-               p = buf;
-               if (KDB_FLAG(CMD_INTERRUPT))
-                       return 0;
-               while (start < end && (c = *KDB_WRAP(start)) &&
-                      (p - buf) < sizeof(buf)-1) {
-                       ++start;
-                       *p++ = c;
-                       if (c == '\n')
-                               break;
+
+       if (skip >= n || skip < 0)
+               return 0;
+
+       kmsg_dump_rewind_nolock(&dumper);
+       while (kmsg_dump_get_line_nolock(&dumper, 1, buf, sizeof(buf), &len)) {
+               if (skip) {
+                       skip--;
+                       continue;
                }
-               *p = '\0';
-               kdb_printf("%s", buf);
+               if (!lines--)
+                       break;
+
+               kdb_printf("%.*s\n", (int)len - 1, buf);
        }
-       if (c != '\n')
-               kdb_printf("\n");
 
        return 0;
 }
index 47c4e56e513ba72ec485afdaa2ad0e30bac6e30f..392ec6a25844c48f1242a649c0c58a1d22c0c783 100644 (file)
@@ -205,7 +205,6 @@ extern char kdb_grep_string[];
 extern int kdb_grep_leading;
 extern int kdb_grep_trailing;
 extern char *kdb_cmds[];
-extern void kdb_syslog_data(char *syslog_data[]);
 extern unsigned long kdb_task_state_string(const char *);
 extern char kdb_task_state_char (const struct task_struct *);
 extern unsigned long kdb_task_state(const struct task_struct *p,
index d7d71d6ec97278cf60fa5b13e79a80bff27b6af2..f1cf0edeb39afa1a3f6543a2f383ac8c4828127b 100644 (file)
@@ -1645,6 +1645,8 @@ perf_install_in_context(struct perf_event_context *ctx,
        lockdep_assert_held(&ctx->mutex);
 
        event->ctx = ctx;
+       if (event->cpu != -1)
+               event->cpu = cpu;
 
        if (!task) {
                /*
@@ -6252,6 +6254,8 @@ SYSCALL_DEFINE5(perf_event_open,
                }
        }
 
+       get_online_cpus();
+
        event = perf_event_alloc(&attr, cpu, task, group_leader, NULL,
                                 NULL, NULL);
        if (IS_ERR(event)) {
@@ -6304,7 +6308,7 @@ SYSCALL_DEFINE5(perf_event_open,
        /*
         * Get the target context (task or percpu):
         */
-       ctx = find_get_context(pmu, task, cpu);
+       ctx = find_get_context(pmu, task, event->cpu);
        if (IS_ERR(ctx)) {
                err = PTR_ERR(ctx);
                goto err_alloc;
@@ -6377,20 +6381,23 @@ SYSCALL_DEFINE5(perf_event_open,
        mutex_lock(&ctx->mutex);
 
        if (move_group) {
-               perf_install_in_context(ctx, group_leader, cpu);
+               synchronize_rcu();
+               perf_install_in_context(ctx, group_leader, event->cpu);
                get_ctx(ctx);
                list_for_each_entry(sibling, &group_leader->sibling_list,
                                    group_entry) {
-                       perf_install_in_context(ctx, sibling, cpu);
+                       perf_install_in_context(ctx, sibling, event->cpu);
                        get_ctx(ctx);
                }
        }
 
-       perf_install_in_context(ctx, event, cpu);
+       perf_install_in_context(ctx, event, event->cpu);
        ++ctx->generation;
        perf_unpin_context(ctx);
        mutex_unlock(&ctx->mutex);
 
+       put_online_cpus();
+
        event->owner = current;
 
        mutex_lock(&current->perf_event_mutex);
@@ -6419,6 +6426,7 @@ err_context:
 err_alloc:
        free_event(event);
 err_task:
+       put_online_cpus();
        if (task)
                put_task_struct(task);
 err_group_fd:
@@ -6479,6 +6487,39 @@ err:
 }
 EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
 
+void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu)
+{
+       struct perf_event_context *src_ctx;
+       struct perf_event_context *dst_ctx;
+       struct perf_event *event, *tmp;
+       LIST_HEAD(events);
+
+       src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx;
+       dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx;
+
+       mutex_lock(&src_ctx->mutex);
+       list_for_each_entry_safe(event, tmp, &src_ctx->event_list,
+                                event_entry) {
+               perf_remove_from_context(event);
+               put_ctx(src_ctx);
+               list_add(&event->event_entry, &events);
+       }
+       mutex_unlock(&src_ctx->mutex);
+
+       synchronize_rcu();
+
+       mutex_lock(&dst_ctx->mutex);
+       list_for_each_entry_safe(event, tmp, &events, event_entry) {
+               list_del(&event->event_entry);
+               if (event->state >= PERF_EVENT_STATE_OFF)
+                       event->state = PERF_EVENT_STATE_INACTIVE;
+               perf_install_in_context(dst_ctx, event, dst_cpu);
+               get_ctx(dst_ctx);
+       }
+       mutex_unlock(&dst_ctx->mutex);
+}
+EXPORT_SYMBOL_GPL(perf_pmu_migrate_context);
+
 static void sync_child_event(struct perf_event *child_event,
                               struct task_struct *child)
 {
index 985be4d80fe8188da34ee47be809faf7b0801ee9..f93532748bca38340f0f2d196b54324a03590480 100644 (file)
 #define UINSNS_PER_PAGE                        (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES)
 #define MAX_UPROBE_XOL_SLOTS           UINSNS_PER_PAGE
 
-static struct srcu_struct uprobes_srcu;
 static struct rb_root uprobes_tree = RB_ROOT;
 
 static DEFINE_SPINLOCK(uprobes_treelock);      /* serialize rbtree access */
 
 #define UPROBES_HASH_SZ        13
 
+/*
+ * We need separate register/unregister and mmap/munmap lock hashes because
+ * of mmap_sem nesting.
+ *
+ * uprobe_register() needs to install probes on (potentially) all processes
+ * and thus needs to acquire multiple mmap_sems (consequtively, not
+ * concurrently), whereas uprobe_mmap() is called while holding mmap_sem
+ * for the particular process doing the mmap.
+ *
+ * uprobe_register()->register_for_each_vma() needs to drop/acquire mmap_sem
+ * because of lock order against i_mmap_mutex. This means there's a hole in
+ * the register vma iteration where a mmap() can happen.
+ *
+ * Thus uprobe_register() can race with uprobe_mmap() and we can try and
+ * install a probe where one is already installed.
+ */
+
 /* serialize (un)register */
 static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
 
@@ -61,17 +77,6 @@ static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ];
  */
 static atomic_t uprobe_events = ATOMIC_INIT(0);
 
-/*
- * Maintain a temporary per vma info that can be used to search if a vma
- * has already been handled. This structure is introduced since extending
- * vm_area_struct wasnt recommended.
- */
-struct vma_info {
-       struct list_head        probe_list;
-       struct mm_struct        *mm;
-       loff_t                  vaddr;
-};
-
 struct uprobe {
        struct rb_node          rb_node;        /* node in the rb tree */
        atomic_t                ref;
@@ -100,7 +105,8 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register)
        if (!is_register)
                return true;
 
-       if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC))
+       if ((vma->vm_flags & (VM_HUGETLB|VM_READ|VM_WRITE|VM_EXEC|VM_SHARED))
+                               == (VM_READ|VM_EXEC))
                return true;
 
        return false;
@@ -129,33 +135,17 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
 static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage)
 {
        struct mm_struct *mm = vma->vm_mm;
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *ptep;
-       spinlock_t *ptl;
        unsigned long addr;
-       int err = -EFAULT;
+       spinlock_t *ptl;
+       pte_t *ptep;
 
        addr = page_address_in_vma(page, vma);
        if (addr == -EFAULT)
-               goto out;
-
-       pgd = pgd_offset(mm, addr);
-       if (!pgd_present(*pgd))
-               goto out;
-
-       pud = pud_offset(pgd, addr);
-       if (!pud_present(*pud))
-               goto out;
-
-       pmd = pmd_offset(pud, addr);
-       if (!pmd_present(*pmd))
-               goto out;
+               return -EFAULT;
 
-       ptep = pte_offset_map_lock(mm, pmd, addr, &ptl);
+       ptep = page_check_address(page, mm, addr, &ptl, 0);
        if (!ptep)
-               goto out;
+               return -EAGAIN;
 
        get_page(kpage);
        page_add_new_anon_rmap(kpage, vma, addr);
@@ -174,10 +164,8 @@ static int __replace_page(struct vm_area_struct *vma, struct page *page, struct
                try_to_free_swap(page);
        put_page(page);
        pte_unmap_unlock(ptep, ptl);
-       err = 0;
 
-out:
-       return err;
+       return 0;
 }
 
 /**
@@ -222,9 +210,8 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
        void *vaddr_old, *vaddr_new;
        struct vm_area_struct *vma;
        struct uprobe *uprobe;
-       loff_t addr;
        int ret;
-
+retry:
        /* Read the page with vaddr into memory */
        ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma);
        if (ret <= 0)
@@ -246,10 +233,6 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
        if (mapping != vma->vm_file->f_mapping)
                goto put_out;
 
-       addr = vma_address(vma, uprobe->offset);
-       if (vaddr != (unsigned long)addr)
-               goto put_out;
-
        ret = -ENOMEM;
        new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
        if (!new_page)
@@ -267,11 +250,7 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
        vaddr_new = kmap_atomic(new_page);
 
        memcpy(vaddr_new, vaddr_old, PAGE_SIZE);
-
-       /* poke the new insn in, ASSUMES we don't cross page boundary */
-       vaddr &= ~PAGE_MASK;
-       BUG_ON(vaddr + UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
-       memcpy(vaddr_new + vaddr, &opcode, UPROBE_SWBP_INSN_SIZE);
+       memcpy(vaddr_new + (vaddr & ~PAGE_MASK), &opcode, UPROBE_SWBP_INSN_SIZE);
 
        kunmap_atomic(vaddr_new);
        kunmap_atomic(vaddr_old);
@@ -291,6 +270,8 @@ unlock_out:
 put_out:
        put_page(old_page);
 
+       if (unlikely(ret == -EAGAIN))
+               goto retry;
        return ret;
 }
 
@@ -312,7 +293,7 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_
        void *vaddr_new;
        int ret;
 
-       ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL);
+       ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
        if (ret <= 0)
                return ret;
 
@@ -333,10 +314,20 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
        uprobe_opcode_t opcode;
        int result;
 
+       if (current->mm == mm) {
+               pagefault_disable();
+               result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr,
+                                                               sizeof(opcode));
+               pagefault_enable();
+
+               if (likely(result == 0))
+                       goto out;
+       }
+
        result = read_opcode(mm, vaddr, &opcode);
        if (result)
                return result;
-
+out:
        if (is_swbp_insn(&opcode))
                return 1;
 
@@ -355,7 +346,9 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
 int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
 {
        int result;
-
+       /*
+        * See the comment near uprobes_hash().
+        */
        result = is_swbp_at_addr(mm, vaddr);
        if (result == 1)
                return -EEXIST;
@@ -520,7 +513,6 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
        uprobe->inode = igrab(inode);
        uprobe->offset = offset;
        init_rwsem(&uprobe->consumer_rwsem);
-       INIT_LIST_HEAD(&uprobe->pending_list);
 
        /* add to uprobes_tree, sorted on inode:offset */
        cur_uprobe = insert_uprobe(uprobe);
@@ -588,20 +580,22 @@ static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc)
 }
 
 static int
-__copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *insn,
-                       unsigned long nbytes, unsigned long offset)
+__copy_insn(struct address_space *mapping, struct file *filp, char *insn,
+                       unsigned long nbytes, loff_t offset)
 {
-       struct file *filp = vma->vm_file;
        struct page *page;
        void *vaddr;
-       unsigned long off1;
-       unsigned long idx;
+       unsigned long off;
+       pgoff_t idx;
 
        if (!filp)
                return -EINVAL;
 
-       idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT);
-       off1 = offset &= ~PAGE_MASK;
+       if (!mapping->a_ops->readpage)
+               return -EIO;
+
+       idx = offset >> PAGE_CACHE_SHIFT;
+       off = offset & ~PAGE_MASK;
 
        /*
         * Ensure that the page that has the original instruction is
@@ -612,22 +606,20 @@ __copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *ins
                return PTR_ERR(page);
 
        vaddr = kmap_atomic(page);
-       memcpy(insn, vaddr + off1, nbytes);
+       memcpy(insn, vaddr + off, nbytes);
        kunmap_atomic(vaddr);
        page_cache_release(page);
 
        return 0;
 }
 
-static int
-copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
+static int copy_insn(struct uprobe *uprobe, struct file *filp)
 {
        struct address_space *mapping;
        unsigned long nbytes;
        int bytes;
 
-       addr &= ~PAGE_MASK;
-       nbytes = PAGE_SIZE - addr;
+       nbytes = PAGE_SIZE - (uprobe->offset & ~PAGE_MASK);
        mapping = uprobe->inode->i_mapping;
 
        /* Instruction at end of binary; copy only available bytes */
@@ -638,13 +630,13 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
 
        /* Instruction at the page-boundary; copy bytes in second page */
        if (nbytes < bytes) {
-               if (__copy_insn(mapping, vma, uprobe->arch.insn + nbytes,
-                               bytes - nbytes, uprobe->offset + nbytes))
-                       return -ENOMEM;
-
+               int err = __copy_insn(mapping, filp, uprobe->arch.insn + nbytes,
+                               bytes - nbytes, uprobe->offset + nbytes);
+               if (err)
+                       return err;
                bytes = nbytes;
        }
-       return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset);
+       return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset);
 }
 
 /*
@@ -672,9 +664,8 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
  */
 static int
 install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
-                       struct vm_area_struct *vma, loff_t vaddr)
+                       struct vm_area_struct *vma, unsigned long vaddr)
 {
-       unsigned long addr;
        int ret;
 
        /*
@@ -687,20 +678,22 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
        if (!uprobe->consumers)
                return -EEXIST;
 
-       addr = (unsigned long)vaddr;
-
        if (!(uprobe->flags & UPROBE_COPY_INSN)) {
-               ret = copy_insn(uprobe, vma, addr);
+               ret = copy_insn(uprobe, vma->vm_file);
                if (ret)
                        return ret;
 
                if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn))
-                       return -EEXIST;
+                       return -ENOTSUPP;
 
-               ret = arch_uprobe_analyze_insn(&uprobe->arch, mm);
+               ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr);
                if (ret)
                        return ret;
 
+               /* write_opcode() assumes we don't cross page boundary */
+               BUG_ON((uprobe->offset & ~PAGE_MASK) +
+                               UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
+
                uprobe->flags |= UPROBE_COPY_INSN;
        }
 
@@ -713,7 +706,7 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
         * Hence increment before and decrement on failure.
         */
        atomic_inc(&mm->uprobes_state.count);
-       ret = set_swbp(&uprobe->arch, mm, addr);
+       ret = set_swbp(&uprobe->arch, mm, vaddr);
        if (ret)
                atomic_dec(&mm->uprobes_state.count);
 
@@ -721,27 +714,21 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
 }
 
 static void
-remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr)
+remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr)
 {
-       if (!set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true))
+       if (!set_orig_insn(&uprobe->arch, mm, vaddr, true))
                atomic_dec(&mm->uprobes_state.count);
 }
 
 /*
- * There could be threads that have hit the breakpoint and are entering the
- * notifier code and trying to acquire the uprobes_treelock. The thread
- * calling delete_uprobe() that is removing the uprobe from the rb_tree can
- * race with these threads and might acquire the uprobes_treelock compared
- * to some of the breakpoint hit threads. In such a case, the breakpoint
- * hit threads will not find the uprobe. The current unregistering thread
- * waits till all other threads have hit a breakpoint, to acquire the
- * uprobes_treelock before the uprobe is removed from the rbtree.
+ * There could be threads that have already hit the breakpoint. They
+ * will recheck the current insn and restart if find_uprobe() fails.
+ * See find_active_uprobe().
  */
 static void delete_uprobe(struct uprobe *uprobe)
 {
        unsigned long flags;
 
-       synchronize_srcu(&uprobes_srcu);
        spin_lock_irqsave(&uprobes_treelock, flags);
        rb_erase(&uprobe->rb_node, &uprobes_tree);
        spin_unlock_irqrestore(&uprobes_treelock, flags);
@@ -750,139 +737,135 @@ static void delete_uprobe(struct uprobe *uprobe)
        atomic_dec(&uprobe_events);
 }
 
-static struct vma_info *
-__find_next_vma_info(struct address_space *mapping, struct list_head *head,
-                       struct vma_info *vi, loff_t offset, bool is_register)
+struct map_info {
+       struct map_info *next;
+       struct mm_struct *mm;
+       unsigned long vaddr;
+};
+
+static inline struct map_info *free_map_info(struct map_info *info)
+{
+       struct map_info *next = info->next;
+       kfree(info);
+       return next;
+}
+
+static struct map_info *
+build_map_info(struct address_space *mapping, loff_t offset, bool is_register)
 {
+       unsigned long pgoff = offset >> PAGE_SHIFT;
        struct prio_tree_iter iter;
        struct vm_area_struct *vma;
-       struct vma_info *tmpvi;
-       unsigned long pgoff;
-       int existing_vma;
-       loff_t vaddr;
-
-       pgoff = offset >> PAGE_SHIFT;
+       struct map_info *curr = NULL;
+       struct map_info *prev = NULL;
+       struct map_info *info;
+       int more = 0;
 
+ again:
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                if (!valid_vma(vma, is_register))
                        continue;
 
-               existing_vma = 0;
-               vaddr = vma_address(vma, offset);
-
-               list_for_each_entry(tmpvi, head, probe_list) {
-                       if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) {
-                               existing_vma = 1;
-                               break;
-                       }
+               if (!prev && !more) {
+                       /*
+                        * Needs GFP_NOWAIT to avoid i_mmap_mutex recursion through
+                        * reclaim. This is optimistic, no harm done if it fails.
+                        */
+                       prev = kmalloc(sizeof(struct map_info),
+                                       GFP_NOWAIT | __GFP_NOMEMALLOC | __GFP_NOWARN);
+                       if (prev)
+                               prev->next = NULL;
                }
-
-               /*
-                * Another vma needs a probe to be installed. However skip
-                * installing the probe if the vma is about to be unlinked.
-                */
-               if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) {
-                       vi->mm = vma->vm_mm;
-                       vi->vaddr = vaddr;
-                       list_add(&vi->probe_list, head);
-
-                       return vi;
+               if (!prev) {
+                       more++;
+                       continue;
                }
-       }
 
-       return NULL;
-}
-
-/*
- * Iterate in the rmap prio tree  and find a vma where a probe has not
- * yet been inserted.
- */
-static struct vma_info *
-find_next_vma_info(struct address_space *mapping, struct list_head *head,
-               loff_t offset, bool is_register)
-{
-       struct vma_info *vi, *retvi;
+               if (!atomic_inc_not_zero(&vma->vm_mm->mm_users))
+                       continue;
 
-       vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL);
-       if (!vi)
-               return ERR_PTR(-ENOMEM);
+               info = prev;
+               prev = prev->next;
+               info->next = curr;
+               curr = info;
 
-       mutex_lock(&mapping->i_mmap_mutex);
-       retvi = __find_next_vma_info(mapping, head, vi, offset, is_register);
+               info->mm = vma->vm_mm;
+               info->vaddr = vma_address(vma, offset);
+       }
        mutex_unlock(&mapping->i_mmap_mutex);
 
-       if (!retvi)
-               kfree(vi);
+       if (!more)
+               goto out;
+
+       prev = curr;
+       while (curr) {
+               mmput(curr->mm);
+               curr = curr->next;
+       }
 
-       return retvi;
+       do {
+               info = kmalloc(sizeof(struct map_info), GFP_KERNEL);
+               if (!info) {
+                       curr = ERR_PTR(-ENOMEM);
+                       goto out;
+               }
+               info->next = prev;
+               prev = info;
+       } while (--more);
+
+       goto again;
+ out:
+       while (prev)
+               prev = free_map_info(prev);
+       return curr;
 }
 
 static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
 {
-       struct list_head try_list;
-       struct vm_area_struct *vma;
-       struct address_space *mapping;
-       struct vma_info *vi, *tmpvi;
-       struct mm_struct *mm;
-       loff_t vaddr;
-       int ret;
+       struct map_info *info;
+       int err = 0;
 
-       mapping = uprobe->inode->i_mapping;
-       INIT_LIST_HEAD(&try_list);
+       info = build_map_info(uprobe->inode->i_mapping,
+                                       uprobe->offset, is_register);
+       if (IS_ERR(info))
+               return PTR_ERR(info);
 
-       ret = 0;
+       while (info) {
+               struct mm_struct *mm = info->mm;
+               struct vm_area_struct *vma;
 
-       for (;;) {
-               vi = find_next_vma_info(mapping, &try_list, uprobe->offset, is_register);
-               if (!vi)
-                       break;
+               if (err)
+                       goto free;
 
-               if (IS_ERR(vi)) {
-                       ret = PTR_ERR(vi);
-                       break;
-               }
+               down_write(&mm->mmap_sem);
+               vma = find_vma(mm, (unsigned long)info->vaddr);
+               if (!vma || !valid_vma(vma, is_register))
+                       goto unlock;
 
-               mm = vi->mm;
-               down_read(&mm->mmap_sem);
-               vma = find_vma(mm, (unsigned long)vi->vaddr);
-               if (!vma || !valid_vma(vma, is_register)) {
-                       list_del(&vi->probe_list);
-                       kfree(vi);
-                       up_read(&mm->mmap_sem);
-                       mmput(mm);
-                       continue;
-               }
-               vaddr = vma_address(vma, uprobe->offset);
                if (vma->vm_file->f_mapping->host != uprobe->inode ||
-                                               vaddr != vi->vaddr) {
-                       list_del(&vi->probe_list);
-                       kfree(vi);
-                       up_read(&mm->mmap_sem);
-                       mmput(mm);
-                       continue;
-               }
-
-               if (is_register)
-                       ret = install_breakpoint(uprobe, mm, vma, vi->vaddr);
-               else
-                       remove_breakpoint(uprobe, mm, vi->vaddr);
+                   vma_address(vma, uprobe->offset) != info->vaddr)
+                       goto unlock;
 
-               up_read(&mm->mmap_sem);
-               mmput(mm);
                if (is_register) {
-                       if (ret && ret == -EEXIST)
-                               ret = 0;
-                       if (ret)
-                               break;
+                       err = install_breakpoint(uprobe, mm, vma, info->vaddr);
+                       /*
+                        * We can race against uprobe_mmap(), see the
+                        * comment near uprobe_hash().
+                        */
+                       if (err == -EEXIST)
+                               err = 0;
+               } else {
+                       remove_breakpoint(uprobe, mm, info->vaddr);
                }
+ unlock:
+               up_write(&mm->mmap_sem);
+ free:
+               mmput(mm);
+               info = free_map_info(info);
        }
 
-       list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) {
-               list_del(&vi->probe_list);
-               kfree(vi);
-       }
-
-       return ret;
+       return err;
 }
 
 static int __uprobe_register(struct uprobe *uprobe)
@@ -1048,7 +1031,7 @@ static void build_probe_list(struct inode *inode, struct list_head *head)
 int uprobe_mmap(struct vm_area_struct *vma)
 {
        struct list_head tmp_list;
-       struct uprobe *uprobe, *u;
+       struct uprobe *uprobe;
        struct inode *inode;
        int ret, count;
 
@@ -1066,12 +1049,9 @@ int uprobe_mmap(struct vm_area_struct *vma)
        ret = 0;
        count = 0;
 
-       list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
-               loff_t vaddr;
-
-               list_del(&uprobe->pending_list);
+       list_for_each_entry(uprobe, &tmp_list, pending_list) {
                if (!ret) {
-                       vaddr = vma_address(vma, uprobe->offset);
+                       loff_t vaddr = vma_address(vma, uprobe->offset);
 
                        if (vaddr < vma->vm_start || vaddr >= vma->vm_end) {
                                put_uprobe(uprobe);
@@ -1079,8 +1059,10 @@ int uprobe_mmap(struct vm_area_struct *vma)
                        }
 
                        ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
-
-                       /* Ignore double add: */
+                       /*
+                        * We can race against uprobe_register(), see the
+                        * comment near uprobe_hash().
+                        */
                        if (ret == -EEXIST) {
                                ret = 0;
 
@@ -1115,7 +1097,7 @@ int uprobe_mmap(struct vm_area_struct *vma)
 void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
        struct list_head tmp_list;
-       struct uprobe *uprobe, *u;
+       struct uprobe *uprobe;
        struct inode *inode;
 
        if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
@@ -1132,11 +1114,8 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
        mutex_lock(uprobes_mmap_hash(inode));
        build_probe_list(inode, &tmp_list);
 
-       list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
-               loff_t vaddr;
-
-               list_del(&uprobe->pending_list);
-               vaddr = vma_address(vma, uprobe->offset);
+       list_for_each_entry(uprobe, &tmp_list, pending_list) {
+               loff_t vaddr = vma_address(vma, uprobe->offset);
 
                if (vaddr >= start && vaddr < end) {
                        /*
@@ -1378,9 +1357,6 @@ void uprobe_free_utask(struct task_struct *t)
 {
        struct uprobe_task *utask = t->utask;
 
-       if (t->uprobe_srcu_id != -1)
-               srcu_read_unlock_raw(&uprobes_srcu, t->uprobe_srcu_id);
-
        if (!utask)
                return;
 
@@ -1398,7 +1374,6 @@ void uprobe_free_utask(struct task_struct *t)
 void uprobe_copy_process(struct task_struct *t)
 {
        t->utask = NULL;
-       t->uprobe_srcu_id = -1;
 }
 
 /*
@@ -1417,7 +1392,6 @@ static struct uprobe_task *add_utask(void)
        if (unlikely(!utask))
                return NULL;
 
-       utask->active_uprobe = NULL;
        current->utask = utask;
        return utask;
 }
@@ -1479,41 +1453,64 @@ static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
        return false;
 }
 
+static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
+{
+       struct mm_struct *mm = current->mm;
+       struct uprobe *uprobe = NULL;
+       struct vm_area_struct *vma;
+
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, bp_vaddr);
+       if (vma && vma->vm_start <= bp_vaddr) {
+               if (valid_vma(vma, false)) {
+                       struct inode *inode;
+                       loff_t offset;
+
+                       inode = vma->vm_file->f_mapping->host;
+                       offset = bp_vaddr - vma->vm_start;
+                       offset += (vma->vm_pgoff << PAGE_SHIFT);
+                       uprobe = find_uprobe(inode, offset);
+               }
+
+               if (!uprobe)
+                       *is_swbp = is_swbp_at_addr(mm, bp_vaddr);
+       } else {
+               *is_swbp = -EFAULT;
+       }
+       up_read(&mm->mmap_sem);
+
+       return uprobe;
+}
+
 /*
  * Run handler and ask thread to singlestep.
  * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
  */
 static void handle_swbp(struct pt_regs *regs)
 {
-       struct vm_area_struct *vma;
        struct uprobe_task *utask;
        struct uprobe *uprobe;
-       struct mm_struct *mm;
        unsigned long bp_vaddr;
+       int uninitialized_var(is_swbp);
 
-       uprobe = NULL;
        bp_vaddr = uprobe_get_swbp_addr(regs);
-       mm = current->mm;
-       down_read(&mm->mmap_sem);
-       vma = find_vma(mm, bp_vaddr);
-
-       if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) {
-               struct inode *inode;
-               loff_t offset;
-
-               inode = vma->vm_file->f_mapping->host;
-               offset = bp_vaddr - vma->vm_start;
-               offset += (vma->vm_pgoff << PAGE_SHIFT);
-               uprobe = find_uprobe(inode, offset);
-       }
-
-       srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id);
-       current->uprobe_srcu_id = -1;
-       up_read(&mm->mmap_sem);
+       uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
 
        if (!uprobe) {
-               /* No matching uprobe; signal SIGTRAP. */
-               send_sig(SIGTRAP, current, 0);
+               if (is_swbp > 0) {
+                       /* No matching uprobe; signal SIGTRAP. */
+                       send_sig(SIGTRAP, current, 0);
+               } else {
+                       /*
+                        * Either we raced with uprobe_unregister() or we can't
+                        * access this memory. The latter is only possible if
+                        * another thread plays with our ->mm. In both cases
+                        * we can simply restart. If this vma was unmapped we
+                        * can pretend this insn was not executed yet and get
+                        * the (correct) SIGSEGV after restart.
+                        */
+                       instruction_pointer_set(regs, bp_vaddr);
+               }
                return;
        }
 
@@ -1620,7 +1617,6 @@ int uprobe_pre_sstep_notifier(struct pt_regs *regs)
                utask->state = UTASK_BP_HIT;
 
        set_thread_flag(TIF_UPROBE);
-       current->uprobe_srcu_id = srcu_read_lock_raw(&uprobes_srcu);
 
        return 1;
 }
@@ -1655,7 +1651,6 @@ static int __init init_uprobes(void)
                mutex_init(&uprobes_mutex[i]);
                mutex_init(&uprobes_mmap_mutex[i]);
        }
-       init_srcu_struct(&uprobes_srcu);
 
        return register_die_notifier(&uprobe_exception_nb);
 }
index 2f59cc334516a9b9e831bb54aa0375c999ae69b2..d17f6c4ddfa9755f4318413805f9b64417b34d47 100644 (file)
@@ -953,14 +953,11 @@ void do_exit(long code)
        exit_signals(tsk);  /* sets PF_EXITING */
        /*
         * tsk->flags are checked in the futex code to protect against
-        * an exiting task cleaning up the robust pi futexes, and in
-        * task_work_add() to avoid the race with exit_task_work().
+        * an exiting task cleaning up the robust pi futexes.
         */
        smp_mb();
        raw_spin_unlock_wait(&tsk->pi_lock);
 
-       exit_task_work(tsk);
-
        if (unlikely(in_atomic()))
                printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
                                current->comm, task_pid_nr(current),
@@ -995,6 +992,7 @@ void do_exit(long code)
        exit_shm(tsk);
        exit_files(tsk);
        exit_fs(tsk);
+       exit_task_work(tsk);
        check_stack_usage();
        exit_thread();
 
index ab5211b9e622cf94d07b7bfb4ccfd9bac85e7b79..ff1cad3b7bdc5eda7d525c165c6aaa4cfe659aec 100644 (file)
@@ -304,12 +304,17 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
        }
 
        err = arch_dup_task_struct(tsk, orig);
-       if (err)
-               goto out;
 
+       /*
+        * We defer looking at err, because we will need this setup
+        * for the clean up path to work correctly.
+        */
        tsk->stack = ti;
-
        setup_thread_stack(tsk, orig);
+
+       if (err)
+               goto out;
+
        clear_user_return_notifier(tsk);
        clear_tsk_need_resched(tsk);
        stackend = end_of_stack(tsk);
@@ -1415,7 +1420,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
         */
        p->group_leader = p;
        INIT_LIST_HEAD(&p->thread_group);
-       INIT_HLIST_HEAD(&p->task_works);
+       p->task_works = NULL;
 
        /* Now that the task is set up, run cgroup callbacks if
         * necessary. We need to run them before the task is visible
index ae34bf51682b4a204de93f62943055350cd5c4d0..6db7a5ed52b58727d33293853053c0fee1d049fe 100644 (file)
@@ -657,6 +657,14 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
        return 0;
 }
 
+static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
+{
+       ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
+       ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
+
+       return ktime_get_update_offsets(offs_real, offs_boot);
+}
+
 /*
  * Retrigger next event is called after clock was set
  *
@@ -665,22 +673,12 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
 static void retrigger_next_event(void *arg)
 {
        struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
-       struct timespec realtime_offset, xtim, wtm, sleep;
 
        if (!hrtimer_hres_active())
                return;
 
-       /* Optimized out for !HIGH_RES */
-       get_xtime_and_monotonic_and_sleep_offset(&xtim, &wtm, &sleep);
-       set_normalized_timespec(&realtime_offset, -wtm.tv_sec, -wtm.tv_nsec);
-
-       /* Adjust CLOCK_REALTIME offset */
        raw_spin_lock(&base->lock);
-       base->clock_base[HRTIMER_BASE_REALTIME].offset =
-               timespec_to_ktime(realtime_offset);
-       base->clock_base[HRTIMER_BASE_BOOTTIME].offset =
-               timespec_to_ktime(sleep);
-
+       hrtimer_update_base(base);
        hrtimer_force_reprogram(base, 0);
        raw_spin_unlock(&base->lock);
 }
@@ -710,13 +708,25 @@ static int hrtimer_switch_to_hres(void)
                base->clock_base[i].resolution = KTIME_HIGH_RES;
 
        tick_setup_sched_timer();
-
        /* "Retrigger" the interrupt to get things going */
        retrigger_next_event(NULL);
        local_irq_restore(flags);
        return 1;
 }
 
+/*
+ * Called from timekeeping code to reprogramm the hrtimer interrupt
+ * device. If called from the timer interrupt context we defer it to
+ * softirq context.
+ */
+void clock_was_set_delayed(void)
+{
+       struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
+
+       cpu_base->clock_was_set = 1;
+       __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+}
+
 #else
 
 static inline int hrtimer_hres_active(void) { return 0; }
@@ -1250,11 +1260,10 @@ void hrtimer_interrupt(struct clock_event_device *dev)
        cpu_base->nr_events++;
        dev->next_event.tv64 = KTIME_MAX;
 
-       entry_time = now = ktime_get();
+       raw_spin_lock(&cpu_base->lock);
+       entry_time = now = hrtimer_update_base(cpu_base);
 retry:
        expires_next.tv64 = KTIME_MAX;
-
-       raw_spin_lock(&cpu_base->lock);
        /*
         * We set expires_next to KTIME_MAX here with cpu_base->lock
         * held to prevent that a timer is enqueued in our queue via
@@ -1330,8 +1339,12 @@ retry:
         * We need to prevent that we loop forever in the hrtimer
         * interrupt routine. We give it 3 attempts to avoid
         * overreacting on some spurious event.
+        *
+        * Acquire base lock for updating the offsets and retrieving
+        * the current time.
         */
-       now = ktime_get();
+       raw_spin_lock(&cpu_base->lock);
+       now = hrtimer_update_base(cpu_base);
        cpu_base->nr_retries++;
        if (++retries < 3)
                goto retry;
@@ -1343,6 +1356,7 @@ retry:
         */
        cpu_base->nr_hangs++;
        cpu_base->hang_detected = 1;
+       raw_spin_unlock(&cpu_base->lock);
        delta = ktime_sub(now, entry_time);
        if (delta.tv64 > cpu_base->max_hang_time.tv64)
                cpu_base->max_hang_time = delta;
@@ -1395,6 +1409,13 @@ void hrtimer_peek_ahead_timers(void)
 
 static void run_hrtimer_softirq(struct softirq_action *h)
 {
+       struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
+
+       if (cpu_base->clock_was_set) {
+               cpu_base->clock_was_set = 0;
+               clock_was_set();
+       }
+
        hrtimer_peek_ahead_timers();
 }
 
index 8c548232ba39daf0f7320d64f19d85775000201a..814c9ef6bba14d7e212d082c659fe83f0f361ce8 100644 (file)
@@ -781,7 +781,7 @@ static void wake_threads_waitq(struct irq_desc *desc)
                wake_up(&desc->wait_for_threads);
 }
 
-static void irq_thread_dtor(struct task_work *unused)
+static void irq_thread_dtor(struct callback_head *unused)
 {
        struct task_struct *tsk = current;
        struct irq_desc *desc;
@@ -813,7 +813,7 @@ static void irq_thread_dtor(struct task_work *unused)
  */
 static int irq_thread(void *data)
 {
-       struct task_work on_exit_work;
+       struct callback_head on_exit_work;
        static const struct sched_param param = {
                .sched_priority = MAX_USER_RT_PRIO/2,
        };
@@ -830,7 +830,7 @@ static int irq_thread(void *data)
 
        sched_setscheduler(current, SCHED_FIFO, &param);
 
-       init_task_work(&on_exit_work, irq_thread_dtor, NULL);
+       init_task_work(&on_exit_work, irq_thread_dtor);
        task_work_add(current, &on_exit_work, false);
 
        while (!irq_wait_for_interrupt(action)) {
index 8f9b4eb974e0bd27e435462433a581a9b42e63b8..a70518c9d82f42c57eb400208ce95dd4dd2aafaa 100644 (file)
@@ -175,7 +175,7 @@ config PM_TEST_SUSPEND
        You probably want to have your system's RTC driver statically
        linked, ensuring that it's available when this test runs.
 
-config CAN_PM_TRACE
+config PM_SLEEP_DEBUG
        def_bool y
        depends on PM_DEBUG && PM_SLEEP
 
@@ -196,7 +196,7 @@ config PM_TRACE
 
 config PM_TRACE_RTC
        bool "Suspend/resume event tracing"
-       depends on CAN_PM_TRACE
+       depends on PM_SLEEP_DEBUG
        depends on X86
        select PM_TRACE
        ---help---
index 8b53db38a279e50a1fe3a8719752fe245201e7a0..b26f5f1e773e6b6aa3420ee1fb60c9b8fc6025cc 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (c) 2003 Open Source Development Lab
  * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>
  * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc.
+ * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
  *
  * This file is released under the GPLv2.
  */
@@ -27,7 +28,6 @@
 #include <linux/syscore_ops.h>
 #include <linux/ctype.h>
 #include <linux/genhd.h>
-#include <scsi/scsi_scan.h>
 
 #include "power.h"
 
@@ -46,6 +46,9 @@ enum {
        HIBERNATION_PLATFORM,
        HIBERNATION_SHUTDOWN,
        HIBERNATION_REBOOT,
+#ifdef CONFIG_SUSPEND
+       HIBERNATION_SUSPEND,
+#endif
        /* keep last */
        __HIBERNATION_AFTER_LAST
 };
@@ -354,6 +357,7 @@ int hibernation_snapshot(int platform_mode)
        }
 
        suspend_console();
+       ftrace_stop();
        pm_restrict_gfp_mask();
 
        error = dpm_suspend(PMSG_FREEZE);
@@ -379,6 +383,7 @@ int hibernation_snapshot(int platform_mode)
        if (error || !in_suspend)
                pm_restore_gfp_mask();
 
+       ftrace_start();
        resume_console();
        dpm_complete(msg);
 
@@ -481,6 +486,7 @@ int hibernation_restore(int platform_mode)
 
        pm_prepare_console();
        suspend_console();
+       ftrace_stop();
        pm_restrict_gfp_mask();
        error = dpm_suspend_start(PMSG_QUIESCE);
        if (!error) {
@@ -488,6 +494,7 @@ int hibernation_restore(int platform_mode)
                dpm_resume_end(PMSG_RECOVER);
        }
        pm_restore_gfp_mask();
+       ftrace_start();
        resume_console();
        pm_restore_console();
        return error;
@@ -514,6 +521,7 @@ int hibernation_platform_enter(void)
 
        entering_platform_hibernation = true;
        suspend_console();
+       ftrace_stop();
        error = dpm_suspend_start(PMSG_HIBERNATE);
        if (error) {
                if (hibernation_ops->recover)
@@ -557,6 +565,7 @@ int hibernation_platform_enter(void)
  Resume_devices:
        entering_platform_hibernation = false;
        dpm_resume_end(PMSG_RESTORE);
+       ftrace_start();
        resume_console();
 
  Close:
@@ -574,6 +583,10 @@ int hibernation_platform_enter(void)
  */
 static void power_down(void)
 {
+#ifdef CONFIG_SUSPEND
+       int error;
+#endif
+
        switch (hibernation_mode) {
        case HIBERNATION_REBOOT:
                kernel_restart(NULL);
@@ -583,6 +596,25 @@ static void power_down(void)
        case HIBERNATION_SHUTDOWN:
                kernel_power_off();
                break;
+#ifdef CONFIG_SUSPEND
+       case HIBERNATION_SUSPEND:
+               error = suspend_devices_and_enter(PM_SUSPEND_MEM);
+               if (error) {
+                       if (hibernation_ops)
+                               hibernation_mode = HIBERNATION_PLATFORM;
+                       else
+                               hibernation_mode = HIBERNATION_SHUTDOWN;
+                       power_down();
+               }
+               /*
+                * Restore swap signature.
+                */
+               error = swsusp_unmark();
+               if (error)
+                       printk(KERN_ERR "PM: Swap will be unusable! "
+                                       "Try swapon -a.\n");
+               return;
+#endif
        }
        kernel_halt();
        /*
@@ -748,13 +780,6 @@ static int software_resume(void)
                        async_synchronize_full();
                }
 
-               /*
-                * We can't depend on SCSI devices being available after loading
-                * one of their modules until scsi_complete_async_scans() is
-                * called and the resume device usually is a SCSI one.
-                */
-               scsi_complete_async_scans();
-
                swsusp_resume_device = name_to_dev_t(resume_file);
                if (!swsusp_resume_device) {
                        error = -ENODEV;
@@ -827,6 +852,9 @@ static const char * const hibernation_modes[] = {
        [HIBERNATION_PLATFORM]  = "platform",
        [HIBERNATION_SHUTDOWN]  = "shutdown",
        [HIBERNATION_REBOOT]    = "reboot",
+#ifdef CONFIG_SUSPEND
+       [HIBERNATION_SUSPEND]   = "suspend",
+#endif
 };
 
 /*
@@ -867,6 +895,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
                switch (i) {
                case HIBERNATION_SHUTDOWN:
                case HIBERNATION_REBOOT:
+#ifdef CONFIG_SUSPEND
+               case HIBERNATION_SUSPEND:
+#endif
                        break;
                case HIBERNATION_PLATFORM:
                        if (hibernation_ops)
@@ -907,6 +938,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
                switch (mode) {
                case HIBERNATION_SHUTDOWN:
                case HIBERNATION_REBOOT:
+#ifdef CONFIG_SUSPEND
+               case HIBERNATION_SUSPEND:
+#endif
                        hibernation_mode = mode;
                        break;
                case HIBERNATION_PLATFORM:
index 428f8a034e9684c50a72f41faf71785822456bd5..f458238109ccd32d195c39b02f1d0cc6efdc09c0 100644 (file)
@@ -235,6 +235,47 @@ late_initcall(pm_debugfs_init);
 
 #endif /* CONFIG_PM_SLEEP */
 
+#ifdef CONFIG_PM_SLEEP_DEBUG
+/*
+ * pm_print_times: print time taken by devices to suspend and resume.
+ *
+ * show() returns whether printing of suspend and resume times is enabled.
+ * store() accepts 0 or 1.  0 disables printing and 1 enables it.
+ */
+bool pm_print_times_enabled;
+
+static ssize_t pm_print_times_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", pm_print_times_enabled);
+}
+
+static ssize_t pm_print_times_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buf, size_t n)
+{
+       unsigned long val;
+
+       if (kstrtoul(buf, 10, &val))
+               return -EINVAL;
+
+       if (val > 1)
+               return -EINVAL;
+
+       pm_print_times_enabled = !!val;
+       return n;
+}
+
+power_attr(pm_print_times);
+
+static inline void pm_print_times_init(void)
+{
+       pm_print_times_enabled = !!initcall_debug;
+}
+#else /* !CONFIG_PP_SLEEP_DEBUG */
+static inline void pm_print_times_init(void) {}
+#endif /* CONFIG_PM_SLEEP_DEBUG */
+
 struct kobject *power_kobj;
 
 /**
@@ -531,6 +572,9 @@ static struct attribute * g[] = {
 #ifdef CONFIG_PM_DEBUG
        &pm_test_attr.attr,
 #endif
+#ifdef CONFIG_PM_SLEEP_DEBUG
+       &pm_print_times_attr.attr,
+#endif
 #endif
        NULL,
 };
@@ -566,6 +610,7 @@ static int __init pm_init(void)
        error = sysfs_create_group(power_kobj, &attr_group);
        if (error)
                return error;
+       pm_print_times_init();
        return pm_autosleep_init();
 }
 
index b0bd4beaebfe7caa84c4c3b4ded37d3e47acacd6..7d4b7ffb3c1d4371f19e81fe83c67ea88ac83759 100644 (file)
@@ -156,6 +156,9 @@ extern void swsusp_free(void);
 extern int swsusp_read(unsigned int *flags_p);
 extern int swsusp_write(unsigned int flags);
 extern void swsusp_close(fmode_t);
+#ifdef CONFIG_SUSPEND
+extern int swsusp_unmark(void);
+#endif
 
 /* kernel/power/block_io.c */
 extern struct block_device *hib_resume_bdev;
index 396d262b8fd01381a99de04d2d310be787b37565..c8b7446b27dfc21add10f610e1692a2f3acee7ed 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/export.h>
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
+#include <linux/ftrace.h>
 #include <trace/events/power.h>
 
 #include "power.h"
@@ -212,6 +213,7 @@ int suspend_devices_and_enter(suspend_state_t state)
                        goto Close;
        }
        suspend_console();
+       ftrace_stop();
        suspend_test_start();
        error = dpm_suspend_start(PMSG_SUSPEND);
        if (error) {
@@ -231,6 +233,7 @@ int suspend_devices_and_enter(suspend_state_t state)
        suspend_test_start();
        dpm_resume_end(PMSG_RESUME);
        suspend_test_finish("resume devices");
+       ftrace_start();
        resume_console();
  Close:
        if (suspend_ops->end)
index 11e22c068e8b25ab8c6ba1127be955d2d4d33e39..3c9d764eb0d8af7e2db7ec99888061a5a573b7ed 100644 (file)
@@ -448,9 +448,9 @@ static int save_image(struct swap_map_handle *handle,
        struct timeval start;
        struct timeval stop;
 
-       printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
+       printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",
                nr_to_write);
-       m = nr_to_write / 100;
+       m = nr_to_write / 10;
        if (!m)
                m = 1;
        nr_pages = 0;
@@ -464,7 +464,8 @@ static int save_image(struct swap_map_handle *handle,
                if (ret)
                        break;
                if (!(nr_pages % m))
-                       printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
+                       printk(KERN_INFO "PM: Image saving progress: %3d%%\n",
+                              nr_pages / m * 10);
                nr_pages++;
        }
        err2 = hib_wait_on_bio_chain(&bio);
@@ -472,9 +473,7 @@ static int save_image(struct swap_map_handle *handle,
        if (!ret)
                ret = err2;
        if (!ret)
-               printk(KERN_CONT "\b\b\b\bdone\n");
-       else
-               printk(KERN_CONT "\n");
+               printk(KERN_INFO "PM: Image saving done.\n");
        swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
        return ret;
 }
@@ -668,9 +667,9 @@ static int save_image_lzo(struct swap_map_handle *handle,
 
        printk(KERN_INFO
                "PM: Using %u thread(s) for compression.\n"
-               "PM: Compressing and saving image data (%u pages) ...     ",
+               "PM: Compressing and saving image data (%u pages)...\n",
                nr_threads, nr_to_write);
-       m = nr_to_write / 100;
+       m = nr_to_write / 10;
        if (!m)
                m = 1;
        nr_pages = 0;
@@ -690,8 +689,10 @@ static int save_image_lzo(struct swap_map_handle *handle,
                                       data_of(*snapshot), PAGE_SIZE);
 
                                if (!(nr_pages % m))
-                                       printk(KERN_CONT "\b\b\b\b%3d%%",
-                                              nr_pages / m);
+                                       printk(KERN_INFO
+                                              "PM: Image saving progress: "
+                                              "%3d%%\n",
+                                              nr_pages / m * 10);
                                nr_pages++;
                        }
                        if (!off)
@@ -761,11 +762,8 @@ out_finish:
        do_gettimeofday(&stop);
        if (!ret)
                ret = err2;
-       if (!ret) {
-               printk(KERN_CONT "\b\b\b\bdone\n");
-       } else {
-               printk(KERN_CONT "\n");
-       }
+       if (!ret)
+               printk(KERN_INFO "PM: Image saving done.\n");
        swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
 out_clean:
        if (crc) {
@@ -973,9 +971,9 @@ static int load_image(struct swap_map_handle *handle,
        int err2;
        unsigned nr_pages;
 
-       printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
+       printk(KERN_INFO "PM: Loading image data pages (%u pages)...\n",
                nr_to_read);
-       m = nr_to_read / 100;
+       m = nr_to_read / 10;
        if (!m)
                m = 1;
        nr_pages = 0;
@@ -993,7 +991,8 @@ static int load_image(struct swap_map_handle *handle,
                if (ret)
                        break;
                if (!(nr_pages % m))
-                       printk("\b\b\b\b%3d%%", nr_pages / m);
+                       printk(KERN_INFO "PM: Image loading progress: %3d%%\n",
+                              nr_pages / m * 10);
                nr_pages++;
        }
        err2 = hib_wait_on_bio_chain(&bio);
@@ -1001,12 +1000,11 @@ static int load_image(struct swap_map_handle *handle,
        if (!ret)
                ret = err2;
        if (!ret) {
-               printk("\b\b\b\bdone\n");
+               printk(KERN_INFO "PM: Image loading done.\n");
                snapshot_write_finalize(snapshot);
                if (!snapshot_image_loaded(snapshot))
                        ret = -ENODATA;
-       } else
-               printk("\n");
+       }
        swsusp_show_speed(&start, &stop, nr_to_read, "Read");
        return ret;
 }
@@ -1185,9 +1183,9 @@ static int load_image_lzo(struct swap_map_handle *handle,
 
        printk(KERN_INFO
                "PM: Using %u thread(s) for decompression.\n"
-               "PM: Loading and decompressing image data (%u pages) ...     ",
+               "PM: Loading and decompressing image data (%u pages)...\n",
                nr_threads, nr_to_read);
-       m = nr_to_read / 100;
+       m = nr_to_read / 10;
        if (!m)
                m = 1;
        nr_pages = 0;
@@ -1319,7 +1317,10 @@ static int load_image_lzo(struct swap_map_handle *handle,
                                       data[thr].unc + off, PAGE_SIZE);
 
                                if (!(nr_pages % m))
-                                       printk("\b\b\b\b%3d%%", nr_pages / m);
+                                       printk(KERN_INFO
+                                              "PM: Image loading progress: "
+                                              "%3d%%\n",
+                                              nr_pages / m * 10);
                                nr_pages++;
 
                                ret = snapshot_write_next(snapshot);
@@ -1344,7 +1345,7 @@ out_finish:
        }
        do_gettimeofday(&stop);
        if (!ret) {
-               printk("\b\b\b\bdone\n");
+               printk(KERN_INFO "PM: Image loading done.\n");
                snapshot_write_finalize(snapshot);
                if (!snapshot_image_loaded(snapshot))
                        ret = -ENODATA;
@@ -1357,8 +1358,7 @@ out_finish:
                                }
                        }
                }
-       } else
-               printk("\n");
+       }
        swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 out_clean:
        for (i = 0; i < ring_size; i++)
@@ -1472,6 +1472,34 @@ void swsusp_close(fmode_t mode)
        blkdev_put(hib_resume_bdev, mode);
 }
 
+/**
+ *      swsusp_unmark - Unmark swsusp signature in the resume device
+ */
+
+#ifdef CONFIG_SUSPEND
+int swsusp_unmark(void)
+{
+       int error;
+
+       hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
+       if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) {
+               memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10);
+               error = hib_bio_write_page(swsusp_resume_block,
+                                       swsusp_header, NULL);
+       } else {
+               printk(KERN_ERR "PM: Cannot find swsusp signature!\n");
+               error = -ENODEV;
+       }
+
+       /*
+        * We just returned from suspend, we don't need the image any more.
+        */
+       free_all_swap_pages(root_swap);
+
+       return error;
+}
+#endif
+
 static int swsusp_header_init(void)
 {
        swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
index 91b0fd021a95d08eef106b3e0b86a41e3a135055..4ed81e74f86fbb2a9d7b0ab8e7d105d0944763c0 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/console.h>
 #include <linux/cpu.h>
 #include <linux/freezer.h>
-#include <scsi/scsi_scan.h>
 
 #include <asm/uaccess.h>
 
@@ -84,7 +83,6 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                 * appear.
                 */
                wait_for_device_probe();
-               scsi_complete_async_scans();
 
                data->swap = -1;
                data->mode = O_WRONLY;
index c8fba3380076afd8db340855340e5886b8497dc6..8f50de394d22b30090d1cf62cd3fd3069d451d57 100644 (file)
@@ -9,6 +9,7 @@
  * manipulate wakelocks on Android.
  */
 
+#include <linux/capability.h>
 #include <linux/ctype.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -188,6 +189,9 @@ int pm_wake_lock(const char *buf)
        size_t len;
        int ret = 0;
 
+       if (!capable(CAP_BLOCK_SUSPEND))
+               return -EPERM;
+
        while (*str && !isspace(*str))
                str++;
 
@@ -231,6 +235,9 @@ int pm_wake_unlock(const char *buf)
        size_t len;
        int ret = 0;
 
+       if (!capable(CAP_BLOCK_SUSPEND))
+               return -EPERM;
+
        len = strlen(buf);
        if (!len)
                return -EINVAL;
index dba18211685ed199b1ea88b9c2439ce8986a8656..ac4bc9e79465ed6cf416d9694f8ddc463e2e77ab 100644 (file)
@@ -194,8 +194,10 @@ static int console_may_schedule;
  */
 
 enum log_flags {
-       LOG_DEFAULT = 0,
-       LOG_NOCONS = 1,         /* already flushed, do not print to console */
+       LOG_NOCONS      = 1,    /* already flushed, do not print to console */
+       LOG_NEWLINE     = 2,    /* text ended with a newline */
+       LOG_PREFIX      = 4,    /* text started with a prefix */
+       LOG_CONT        = 8,    /* text is a fragment of a continuation line */
 };
 
 struct log {
@@ -217,6 +219,8 @@ static DEFINE_RAW_SPINLOCK(logbuf_lock);
 /* the next printk record to read by syslog(READ) or /proc/kmsg */
 static u64 syslog_seq;
 static u32 syslog_idx;
+static enum log_flags syslog_prev;
+static size_t syslog_partial;
 
 /* index and sequence number of the first record stored in the buffer */
 static u64 log_first_seq;
@@ -430,20 +434,20 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
        ret = mutex_lock_interruptible(&user->lock);
        if (ret)
                return ret;
-       raw_spin_lock(&logbuf_lock);
+       raw_spin_lock_irq(&logbuf_lock);
        while (user->seq == log_next_seq) {
                if (file->f_flags & O_NONBLOCK) {
                        ret = -EAGAIN;
-                       raw_spin_unlock(&logbuf_lock);
+                       raw_spin_unlock_irq(&logbuf_lock);
                        goto out;
                }
 
-               raw_spin_unlock(&logbuf_lock);
+               raw_spin_unlock_irq(&logbuf_lock);
                ret = wait_event_interruptible(log_wait,
                                               user->seq != log_next_seq);
                if (ret)
                        goto out;
-               raw_spin_lock(&logbuf_lock);
+               raw_spin_lock_irq(&logbuf_lock);
        }
 
        if (user->seq < log_first_seq) {
@@ -451,7 +455,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
                user->idx = log_first_idx;
                user->seq = log_first_seq;
                ret = -EPIPE;
-               raw_spin_unlock(&logbuf_lock);
+               raw_spin_unlock_irq(&logbuf_lock);
                goto out;
        }
 
@@ -465,7 +469,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
        for (i = 0; i < msg->text_len; i++) {
                unsigned char c = log_text(msg)[i];
 
-               if (c < ' ' || c >= 128)
+               if (c < ' ' || c >= 127 || c == '\\')
                        len += sprintf(user->buf + len, "\\x%02x", c);
                else
                        user->buf[len++] = c;
@@ -489,7 +493,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
                                continue;
                        }
 
-                       if (c < ' ' || c >= 128) {
+                       if (c < ' ' || c >= 127 || c == '\\') {
                                len += sprintf(user->buf + len, "\\x%02x", c);
                                continue;
                        }
@@ -501,7 +505,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
 
        user->idx = log_next(user->idx);
        user->seq++;
-       raw_spin_unlock(&logbuf_lock);
+       raw_spin_unlock_irq(&logbuf_lock);
 
        if (len > count) {
                ret = -EINVAL;
@@ -528,7 +532,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
        if (offset)
                return -ESPIPE;
 
-       raw_spin_lock(&logbuf_lock);
+       raw_spin_lock_irq(&logbuf_lock);
        switch (whence) {
        case SEEK_SET:
                /* the first record */
@@ -552,7 +556,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
        default:
                ret = -EINVAL;
        }
-       raw_spin_unlock(&logbuf_lock);
+       raw_spin_unlock_irq(&logbuf_lock);
        return ret;
 }
 
@@ -566,14 +570,14 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
 
        poll_wait(file, &log_wait, wait);
 
-       raw_spin_lock(&logbuf_lock);
+       raw_spin_lock_irq(&logbuf_lock);
        if (user->seq < log_next_seq) {
                /* return error when data has vanished underneath us */
                if (user->seq < log_first_seq)
                        ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
                ret = POLLIN|POLLRDNORM;
        }
-       raw_spin_unlock(&logbuf_lock);
+       raw_spin_unlock_irq(&logbuf_lock);
 
        return ret;
 }
@@ -597,10 +601,10 @@ static int devkmsg_open(struct inode *inode, struct file *file)
 
        mutex_init(&user->lock);
 
-       raw_spin_lock(&logbuf_lock);
+       raw_spin_lock_irq(&logbuf_lock);
        user->idx = log_first_idx;
        user->seq = log_first_seq;
-       raw_spin_unlock(&logbuf_lock);
+       raw_spin_unlock_irq(&logbuf_lock);
 
        file->private_data = user;
        return 0;
@@ -818,15 +822,18 @@ static size_t print_time(u64 ts, char *buf)
 static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
 {
        size_t len = 0;
+       unsigned int prefix = (msg->facility << 3) | msg->level;
 
        if (syslog) {
                if (buf) {
-                       len += sprintf(buf, "<%u>", msg->level);
+                       len += sprintf(buf, "<%u>", prefix);
                } else {
                        len += 3;
-                       if (msg->level > 9)
-                               len++;
-                       if (msg->level > 99)
+                       if (prefix > 999)
+                               len += 3;
+                       else if (prefix > 99)
+                               len += 2;
+                       else if (prefix > 9)
                                len++;
                }
        }
@@ -835,13 +842,26 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
        return len;
 }
 
-static size_t msg_print_text(const struct log *msg, bool syslog,
-                            char *buf, size_t size)
+static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+                            bool syslog, char *buf, size_t size)
 {
        const char *text = log_text(msg);
        size_t text_size = msg->text_len;
+       bool prefix = true;
+       bool newline = true;
        size_t len = 0;
 
+       if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX))
+               prefix = false;
+
+       if (msg->flags & LOG_CONT) {
+               if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE))
+                       prefix = false;
+
+               if (!(msg->flags & LOG_NEWLINE))
+                       newline = false;
+       }
+
        do {
                const char *next = memchr(text, '\n', text_size);
                size_t text_len;
@@ -859,16 +879,22 @@ static size_t msg_print_text(const struct log *msg, bool syslog,
                            text_len + 1>= size - len)
                                break;
 
-                       len += print_prefix(msg, syslog, buf + len);
+                       if (prefix)
+                               len += print_prefix(msg, syslog, buf + len);
                        memcpy(buf + len, text, text_len);
                        len += text_len;
-                       buf[len++] = '\n';
+                       if (next || newline)
+                               buf[len++] = '\n';
                } else {
                        /* SYSLOG_ACTION_* buffer size only calculation */
-                       len += print_prefix(msg, syslog, NULL);
-                       len += text_len + 1;
+                       if (prefix)
+                               len += print_prefix(msg, syslog, NULL);
+                       len += text_len;
+                       if (next || newline)
+                               len++;
                }
 
+               prefix = true;
                text = next;
        } while (text);
 
@@ -887,22 +913,35 @@ static int syslog_print(char __user *buf, int size)
 
        while (size > 0) {
                size_t n;
+               size_t skip;
 
                raw_spin_lock_irq(&logbuf_lock);
                if (syslog_seq < log_first_seq) {
                        /* messages are gone, move to first one */
                        syslog_seq = log_first_seq;
                        syslog_idx = log_first_idx;
+                       syslog_prev = 0;
+                       syslog_partial = 0;
                }
                if (syslog_seq == log_next_seq) {
                        raw_spin_unlock_irq(&logbuf_lock);
                        break;
                }
+
+               skip = syslog_partial;
                msg = log_from_idx(syslog_idx);
-               n = msg_print_text(msg, true, text, LOG_LINE_MAX);
-               if (n <= size) {
+               n = msg_print_text(msg, syslog_prev, true, text, LOG_LINE_MAX);
+               if (n - syslog_partial <= size) {
+                       /* message fits into buffer, move forward */
                        syslog_idx = log_next(syslog_idx);
                        syslog_seq++;
+                       syslog_prev = msg->flags;
+                       n -= syslog_partial;
+                       syslog_partial = 0;
+               } else if (!len){
+                       /* partial read(), remember position */
+                       n = size;
+                       syslog_partial += n;
                } else
                        n = 0;
                raw_spin_unlock_irq(&logbuf_lock);
@@ -910,17 +949,15 @@ static int syslog_print(char __user *buf, int size)
                if (!n)
                        break;
 
-               len += n;
-               size -= n;
-               buf += n;
-               n = copy_to_user(buf - n, text, n);
-
-               if (n) {
-                       len -= n;
+               if (copy_to_user(buf, text + skip, n)) {
                        if (!len)
                                len = -EFAULT;
                        break;
                }
+
+               len += n;
+               size -= n;
+               buf += n;
        }
 
        kfree(text);
@@ -941,6 +978,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                u64 next_seq;
                u64 seq;
                u32 idx;
+               enum log_flags prev;
 
                if (clear_seq < log_first_seq) {
                        /* messages are gone, move to first available one */
@@ -954,10 +992,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                 */
                seq = clear_seq;
                idx = clear_idx;
+               prev = 0;
                while (seq < log_next_seq) {
                        struct log *msg = log_from_idx(idx);
 
-                       len += msg_print_text(msg, true, NULL, 0);
+                       len += msg_print_text(msg, prev, true, NULL, 0);
                        idx = log_next(idx);
                        seq++;
                }
@@ -965,10 +1004,11 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                /* move first record forward until length fits into the buffer */
                seq = clear_seq;
                idx = clear_idx;
+               prev = 0;
                while (len > size && seq < log_next_seq) {
                        struct log *msg = log_from_idx(idx);
 
-                       len -= msg_print_text(msg, true, NULL, 0);
+                       len -= msg_print_text(msg, prev, true, NULL, 0);
                        idx = log_next(idx);
                        seq++;
                }
@@ -977,17 +1017,19 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                next_seq = log_next_seq;
 
                len = 0;
+               prev = 0;
                while (len >= 0 && seq < next_seq) {
                        struct log *msg = log_from_idx(idx);
                        int textlen;
 
-                       textlen = msg_print_text(msg, true, text, LOG_LINE_MAX);
+                       textlen = msg_print_text(msg, prev, true, text, LOG_LINE_MAX);
                        if (textlen < 0) {
                                len = textlen;
                                break;
                        }
                        idx = log_next(idx);
                        seq++;
+                       prev = msg->flags;
 
                        raw_spin_unlock_irq(&logbuf_lock);
                        if (copy_to_user(buf + len, text, textlen))
@@ -1000,6 +1042,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                                /* messages are gone, move to next one */
                                seq = log_first_seq;
                                idx = log_first_idx;
+                               prev = 0;
                        }
                }
        }
@@ -1018,7 +1061,6 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
 {
        bool clear = false;
        static int saved_console_loglevel = -1;
-       static DEFINE_MUTEX(syslog_mutex);
        int error;
 
        error = check_syslog_permissions(type, from_file);
@@ -1045,17 +1087,11 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
                        error = -EFAULT;
                        goto out;
                }
-               error = mutex_lock_interruptible(&syslog_mutex);
-               if (error)
-                       goto out;
                error = wait_event_interruptible(log_wait,
                                                 syslog_seq != log_next_seq);
-               if (error) {
-                       mutex_unlock(&syslog_mutex);
+               if (error)
                        goto out;
-               }
                error = syslog_print(buf, len);
-               mutex_unlock(&syslog_mutex);
                break;
        /* Read/clear last kernel messages */
        case SYSLOG_ACTION_READ_CLEAR:
@@ -1111,6 +1147,8 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
                        /* messages are gone, move to first one */
                        syslog_seq = log_first_seq;
                        syslog_idx = log_first_idx;
+                       syslog_prev = 0;
+                       syslog_partial = 0;
                }
                if (from_file) {
                        /*
@@ -1120,19 +1158,20 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
                         */
                        error = log_next_idx - syslog_idx;
                } else {
-                       u64 seq;
-                       u32 idx;
+                       u64 seq = syslog_seq;
+                       u32 idx = syslog_idx;
+                       enum log_flags prev = syslog_prev;
 
                        error = 0;
-                       seq = syslog_seq;
-                       idx = syslog_idx;
                        while (seq < log_next_seq) {
                                struct log *msg = log_from_idx(idx);
 
-                               error += msg_print_text(msg, true, NULL, 0);
+                               error += msg_print_text(msg, prev, true, NULL, 0);
                                idx = log_next(idx);
                                seq++;
+                               prev = msg->flags;
                        }
+                       error -= syslog_partial;
                }
                raw_spin_unlock_irq(&logbuf_lock);
                break;
@@ -1153,21 +1192,6 @@ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
        return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
 }
 
-#ifdef CONFIG_KGDB_KDB
-/* kdb dmesg command needs access to the syslog buffer.  do_syslog()
- * uses locks so it cannot be used during debugging.  Just tell kdb
- * where the start and end of the physical and logical logs are.  This
- * is equivalent to do_syslog(3).
- */
-void kdb_syslog_data(char *syslog_data[4])
-{
-       syslog_data[0] = log_buf;
-       syslog_data[1] = log_buf + log_buf_len;
-       syslog_data[2] = log_buf + log_first_idx;
-       syslog_data[3] = log_buf + log_next_idx;
-}
-#endif /* CONFIG_KGDB_KDB */
-
 static bool __read_mostly ignore_loglevel;
 
 static int __init ignore_loglevel_setup(char *str)
@@ -1400,10 +1424,9 @@ asmlinkage int vprintk_emit(int facility, int level,
        static char textbuf[LOG_LINE_MAX];
        char *text = textbuf;
        size_t text_len;
+       enum log_flags lflags = 0;
        unsigned long flags;
        int this_cpu;
-       bool newline = false;
-       bool prefix = false;
        int printed_len = 0;
 
        boot_delay_msec();
@@ -1442,7 +1465,7 @@ asmlinkage int vprintk_emit(int facility, int level,
                recursion_bug = 0;
                printed_len += strlen(recursion_msg);
                /* emit KERN_CRIT message */
-               log_store(0, 2, LOG_DEFAULT, 0,
+               log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
                          NULL, 0, recursion_msg, printed_len);
        }
 
@@ -1455,7 +1478,7 @@ asmlinkage int vprintk_emit(int facility, int level,
        /* mark and strip a trailing newline */
        if (text_len && text[text_len-1] == '\n') {
                text_len--;
-               newline = true;
+               lflags |= LOG_NEWLINE;
        }
 
        /* strip syslog prefix and extract log level or control flags */
@@ -1465,7 +1488,7 @@ asmlinkage int vprintk_emit(int facility, int level,
                        if (level == -1)
                                level = text[1] - '0';
                case 'd':       /* KERN_DEFAULT */
-                       prefix = true;
+                       lflags |= LOG_PREFIX;
                case 'c':       /* KERN_CONT */
                        text += 3;
                        text_len -= 3;
@@ -1475,22 +1498,20 @@ asmlinkage int vprintk_emit(int facility, int level,
        if (level == -1)
                level = default_message_loglevel;
 
-       if (dict) {
-               prefix = true;
-               newline = true;
-       }
+       if (dict)
+               lflags |= LOG_PREFIX|LOG_NEWLINE;
 
-       if (!newline) {
+       if (!(lflags & LOG_NEWLINE)) {
                /*
                 * Flush the conflicting buffer. An earlier newline was missing,
                 * or another task also prints continuation lines.
                 */
-               if (cont.len && (prefix || cont.owner != current))
+               if (cont.len && (lflags & LOG_PREFIX || cont.owner != current))
                        cont_flush();
 
                /* buffer line if possible, otherwise store it right away */
                if (!cont_add(facility, level, text, text_len))
-                       log_store(facility, level, LOG_DEFAULT, 0,
+                       log_store(facility, level, lflags | LOG_CONT, 0,
                                  dict, dictlen, text, text_len);
        } else {
                bool stored = false;
@@ -1502,13 +1523,13 @@ asmlinkage int vprintk_emit(int facility, int level,
                 * flush it out and store this line separately.
                 */
                if (cont.len && cont.owner == current) {
-                       if (!prefix)
+                       if (!(lflags & LOG_PREFIX))
                                stored = cont_add(facility, level, text, text_len);
                        cont_flush();
                }
 
                if (!stored)
-                       log_store(facility, level, LOG_DEFAULT, 0,
+                       log_store(facility, level, lflags, 0,
                                  dict, dictlen, text, text_len);
        }
        printed_len += text_len;
@@ -1607,8 +1628,8 @@ static struct cont {
 static struct log *log_from_idx(u32 idx) { return NULL; }
 static u32 log_next(u32 idx) { return 0; }
 static void call_console_drivers(int level, const char *text, size_t len) {}
-static size_t msg_print_text(const struct log *msg, bool syslog,
-                            char *buf, size_t size) { return 0; }
+static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+                            bool syslog, char *buf, size_t size) { return 0; }
 static size_t cont_print_text(char *text, size_t size) { return 0; }
 
 #endif /* CONFIG_PRINTK */
@@ -1884,6 +1905,7 @@ void wake_up_klogd(void)
 /* the next printk record to write to the console */
 static u64 console_seq;
 static u32 console_idx;
+static enum log_flags console_prev;
 
 /**
  * console_unlock - unlock the console system
@@ -1944,6 +1966,7 @@ again:
                        /* messages are gone, move to first one */
                        console_seq = log_first_seq;
                        console_idx = log_first_idx;
+                       console_prev = 0;
                }
 skip:
                if (console_seq == log_next_seq)
@@ -1957,14 +1980,21 @@ skip:
                         */
                        console_idx = log_next(console_idx);
                        console_seq++;
+                       /*
+                        * We will get here again when we register a new
+                        * CON_PRINTBUFFER console. Clear the flag so we
+                        * will properly dump everything later.
+                        */
+                       msg->flags &= ~LOG_NOCONS;
                        goto skip;
                }
 
                level = msg->level;
-               len = msg_print_text(msg, false, text, sizeof(text));
-
+               len = msg_print_text(msg, console_prev, false,
+                                    text, sizeof(text));
                console_idx = log_next(console_idx);
                console_seq++;
+               console_prev = msg->flags;
                raw_spin_unlock(&logbuf_lock);
 
                stop_critical_timings();        /* don't trace print latency */
@@ -2227,6 +2257,7 @@ void register_console(struct console *newcon)
                raw_spin_lock_irqsave(&logbuf_lock, flags);
                console_seq = syslog_seq;
                console_idx = syslog_idx;
+               console_prev = syslog_prev;
                raw_spin_unlock_irqrestore(&logbuf_lock, flags);
                /*
                 * We're about to replay the log buffer.  Only do this to the
@@ -2479,7 +2510,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
 }
 
 /**
- * kmsg_dump_get_line - retrieve one kmsg log line
+ * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version)
  * @dumper: registered kmsg dumper
  * @syslog: include the "<4>" prefixes
  * @line: buffer to copy the line to
@@ -2494,11 +2525,12 @@ void kmsg_dump(enum kmsg_dump_reason reason)
  *
  * A return value of FALSE indicates that there are no more records to
  * read.
+ *
+ * The function is similar to kmsg_dump_get_line(), but grabs no locks.
  */
-bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
-                       char *line, size_t size, size_t *len)
+bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
+                              char *line, size_t size, size_t *len)
 {
-       unsigned long flags;
        struct log *msg;
        size_t l = 0;
        bool ret = false;
@@ -2506,7 +2538,6 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
        if (!dumper->active)
                goto out;
 
-       raw_spin_lock_irqsave(&logbuf_lock, flags);
        if (dumper->cur_seq < log_first_seq) {
                /* messages are gone, move to first available one */
                dumper->cur_seq = log_first_seq;
@@ -2514,24 +2545,50 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
        }
 
        /* last entry */
-       if (dumper->cur_seq >= log_next_seq) {
-               raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+       if (dumper->cur_seq >= log_next_seq)
                goto out;
-       }
 
        msg = log_from_idx(dumper->cur_idx);
-       l = msg_print_text(msg, syslog,
-                             line, size);
+       l = msg_print_text(msg, 0, syslog, line, size);
 
        dumper->cur_idx = log_next(dumper->cur_idx);
        dumper->cur_seq++;
        ret = true;
-       raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 out:
        if (len)
                *len = l;
        return ret;
 }
+
+/**
+ * kmsg_dump_get_line - retrieve one kmsg log line
+ * @dumper: registered kmsg dumper
+ * @syslog: include the "<4>" prefixes
+ * @line: buffer to copy the line to
+ * @size: maximum size of the buffer
+ * @len: length of line placed into buffer
+ *
+ * Start at the beginning of the kmsg buffer, with the oldest kmsg
+ * record, and copy one record into the provided buffer.
+ *
+ * Consecutive calls will return the next available record moving
+ * towards the end of the buffer with the youngest messages.
+ *
+ * A return value of FALSE indicates that there are no more records to
+ * read.
+ */
+bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
+                       char *line, size_t size, size_t *len)
+{
+       unsigned long flags;
+       bool ret;
+
+       raw_spin_lock_irqsave(&logbuf_lock, flags);
+       ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
+       raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(kmsg_dump_get_line);
 
 /**
@@ -2561,6 +2618,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        u32 idx;
        u64 next_seq;
        u32 next_idx;
+       enum log_flags prev;
        size_t l = 0;
        bool ret = false;
 
@@ -2583,23 +2641,27 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        /* calculate length of entire buffer */
        seq = dumper->cur_seq;
        idx = dumper->cur_idx;
+       prev = 0;
        while (seq < dumper->next_seq) {
                struct log *msg = log_from_idx(idx);
 
-               l += msg_print_text(msg, true, NULL, 0);
+               l += msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
                seq++;
+               prev = msg->flags;
        }
 
        /* move first record forward until length fits into the buffer */
        seq = dumper->cur_seq;
        idx = dumper->cur_idx;
+       prev = 0;
        while (l > size && seq < dumper->next_seq) {
                struct log *msg = log_from_idx(idx);
 
-               l -= msg_print_text(msg, true, NULL, 0);
+               l -= msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
                seq++;
+               prev = msg->flags;
        }
 
        /* last message in next interation */
@@ -2607,14 +2669,14 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        next_idx = idx;
 
        l = 0;
+       prev = 0;
        while (seq < dumper->next_seq) {
                struct log *msg = log_from_idx(idx);
 
-               l += msg_print_text(msg, syslog,
-                                   buf + l, size - l);
-
+               l += msg_print_text(msg, prev, syslog, buf + l, size - l);
                idx = log_next(idx);
                seq++;
+               prev = msg->flags;
        }
 
        dumper->next_seq = next_seq;
@@ -2628,6 +2690,24 @@ out:
 }
 EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer);
 
+/**
+ * kmsg_dump_rewind_nolock - reset the interator (unlocked version)
+ * @dumper: registered kmsg dumper
+ *
+ * Reset the dumper's iterator so that kmsg_dump_get_line() and
+ * kmsg_dump_get_buffer() can be called again and used multiple
+ * times within the same dumper.dump() callback.
+ *
+ * The function is similar to kmsg_dump_rewind(), but grabs no locks.
+ */
+void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper)
+{
+       dumper->cur_seq = clear_seq;
+       dumper->cur_idx = clear_idx;
+       dumper->next_seq = log_next_seq;
+       dumper->next_idx = log_next_idx;
+}
+
 /**
  * kmsg_dump_rewind - reset the interator
  * @dumper: registered kmsg dumper
@@ -2641,10 +2721,7 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
        unsigned long flags;
 
        raw_spin_lock_irqsave(&logbuf_lock, flags);
-       dumper->cur_seq = clear_seq;
-       dumper->cur_idx = clear_idx;
-       dumper->next_seq = log_next_seq;
-       dumper->next_idx = log_next_idx;
+       kmsg_dump_rewind_nolock(dumper);
        raw_spin_unlock_irqrestore(&logbuf_lock, flags);
 }
 EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
index 95cba41ce1e9a10568bf17a403b637b57a822d62..4e6a61b15e86fe0e27fc30d80775de4f4c8c47e6 100644 (file)
 
 #ifdef CONFIG_PREEMPT_RCU
 
+/*
+ * Preemptible RCU implementation for rcu_read_lock().
+ * Just increment ->rcu_read_lock_nesting, shared state will be updated
+ * if we block.
+ */
+void __rcu_read_lock(void)
+{
+       current->rcu_read_lock_nesting++;
+       barrier();  /* critical section after entry code. */
+}
+EXPORT_SYMBOL_GPL(__rcu_read_lock);
+
+/*
+ * Preemptible RCU implementation for rcu_read_unlock().
+ * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
+ * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
+ * invoke rcu_read_unlock_special() to clean up after a context switch
+ * in an RCU read-side critical section and other special cases.
+ */
+void __rcu_read_unlock(void)
+{
+       struct task_struct *t = current;
+
+       if (t->rcu_read_lock_nesting != 1) {
+               --t->rcu_read_lock_nesting;
+       } else {
+               barrier();  /* critical section before exit code. */
+               t->rcu_read_lock_nesting = INT_MIN;
+               barrier();  /* assign before ->rcu_read_unlock_special load */
+               if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
+                       rcu_read_unlock_special(t);
+               barrier();  /* ->rcu_read_unlock_special load before assign */
+               t->rcu_read_lock_nesting = 0;
+       }
+#ifdef CONFIG_PROVE_LOCKING
+       {
+               int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
+
+               WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
+       }
+#endif /* #ifdef CONFIG_PROVE_LOCKING */
+}
+EXPORT_SYMBOL_GPL(__rcu_read_unlock);
+
 /*
  * Check for a task exiting while in a preemptible-RCU read-side
  * critical section, clean up if so.  No need to issue warnings,
index 37a5444204d2895193b8ffafbe8b7552c0f83acc..547b1fe5b052c4000a3747c58c3852aa618ae184 100644 (file)
@@ -172,7 +172,7 @@ void rcu_irq_enter(void)
        local_irq_restore(flags);
 }
 
-#ifdef CONFIG_PROVE_RCU
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
 
 /*
  * Test whether RCU thinks that the current CPU is idle.
@@ -183,7 +183,7 @@ int rcu_is_cpu_idle(void)
 }
 EXPORT_SYMBOL(rcu_is_cpu_idle);
 
-#endif /* #ifdef CONFIG_PROVE_RCU */
+#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
 /*
  * Test whether the current CPU was interrupted from idle.  Nested
index fc31a2d651005dd6a912bd3487795975e33740e3..918fd1e8509c9d5589d9ff75d0f63bca0b27cc32 100644 (file)
@@ -132,7 +132,6 @@ static struct rcu_preempt_ctrlblk rcu_preempt_ctrlblk = {
        RCU_TRACE(.rcb.name = "rcu_preempt")
 };
 
-static void rcu_read_unlock_special(struct task_struct *t);
 static int rcu_preempted_readers_exp(void);
 static void rcu_report_exp_done(void);
 
@@ -351,8 +350,9 @@ static int rcu_initiate_boost(void)
                        rcu_preempt_ctrlblk.boost_tasks =
                                rcu_preempt_ctrlblk.gp_tasks;
                invoke_rcu_callbacks();
-       } else
+       } else {
                RCU_TRACE(rcu_initiate_boost_trace());
+       }
        return 1;
 }
 
@@ -526,24 +526,12 @@ void rcu_preempt_note_context_switch(void)
        local_irq_restore(flags);
 }
 
-/*
- * Tiny-preemptible RCU implementation for rcu_read_lock().
- * Just increment ->rcu_read_lock_nesting, shared state will be updated
- * if we block.
- */
-void __rcu_read_lock(void)
-{
-       current->rcu_read_lock_nesting++;
-       barrier();  /* needed if we ever invoke rcu_read_lock in rcutiny.c */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_lock);
-
 /*
  * Handle special cases during rcu_read_unlock(), such as needing to
  * notify RCU core processing or task having blocked during the RCU
  * read-side critical section.
  */
-static noinline void rcu_read_unlock_special(struct task_struct *t)
+void rcu_read_unlock_special(struct task_struct *t)
 {
        int empty;
        int empty_exp;
@@ -626,38 +614,6 @@ static noinline void rcu_read_unlock_special(struct task_struct *t)
        local_irq_restore(flags);
 }
 
-/*
- * Tiny-preemptible RCU implementation for rcu_read_unlock().
- * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
- * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
- * invoke rcu_read_unlock_special() to clean up after a context switch
- * in an RCU read-side critical section and other special cases.
- */
-void __rcu_read_unlock(void)
-{
-       struct task_struct *t = current;
-
-       barrier();  /* needed if we ever invoke rcu_read_unlock in rcutiny.c */
-       if (t->rcu_read_lock_nesting != 1)
-               --t->rcu_read_lock_nesting;
-       else {
-               t->rcu_read_lock_nesting = INT_MIN;
-               barrier();  /* assign before ->rcu_read_unlock_special load */
-               if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
-                       rcu_read_unlock_special(t);
-               barrier();  /* ->rcu_read_unlock_special load before assign */
-               t->rcu_read_lock_nesting = 0;
-       }
-#ifdef CONFIG_PROVE_LOCKING
-       {
-               int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
-
-               WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
-       }
-#endif /* #ifdef CONFIG_PROVE_LOCKING */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_unlock);
-
 /*
  * Check for a quiescent state from the current CPU.  When a task blocks,
  * the task is recorded in the rcu_preempt_ctrlblk structure, which is
@@ -823,9 +779,9 @@ void synchronize_rcu_expedited(void)
                rpcp->exp_tasks = NULL;
 
        /* Wait for tail of ->blkd_tasks list to drain. */
-       if (!rcu_preempted_readers_exp())
+       if (!rcu_preempted_readers_exp()) {
                local_irq_restore(flags);
-       else {
+       else {
                rcu_initiate_boost();
                local_irq_restore(flags);
                wait_event(sync_rcu_preempt_exp_wq,
@@ -846,8 +802,6 @@ EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
  */
 int rcu_preempt_needs_cpu(void)
 {
-       if (!rcu_preempt_running_reader())
-               rcu_preempt_cpu_qs();
        return rcu_preempt_ctrlblk.rcb.rcucblist != NULL;
 }
 
index e66b34ab7555f9153a8c5955678d73fc87b6d777..25b15033c61f88ff7d76854fd16401779d9d9f62 100644 (file)
@@ -49,8 +49,7 @@
 #include <asm/byteorder.h>
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
-             "Josh Triplett <josh@freedesktop.org>");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");
 
 static int nreaders = -1;      /* # reader threads, defaults to 2*ncpus */
 static int nfakewriters = 4;   /* # fake writer threads */
@@ -206,6 +205,7 @@ 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);
@@ -407,8 +407,9 @@ rcu_torture_cb(struct rcu_head *p)
        if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
                rp->rtort_mbtest = 0;
                rcu_torture_free(rp);
-       } else
+       } else {
                cur_ops->deferred_free(rp);
+       }
 }
 
 static int rcu_no_completed(void)
@@ -635,6 +636,17 @@ 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 int srcu_torture_stats(char *page)
 {
        int cnt = 0;
@@ -661,8 +673,8 @@ static struct rcu_torture_ops srcu_ops = {
        .completed      = srcu_torture_completed,
        .deferred_free  = srcu_torture_deferred_free,
        .sync           = srcu_torture_synchronize,
-       .call           = NULL,
-       .cb_barrier     = NULL,
+       .call           = srcu_torture_call,
+       .cb_barrier     = srcu_torture_barrier,
        .stats          = srcu_torture_stats,
        .name           = "srcu"
 };
@@ -1013,7 +1025,11 @@ rcu_torture_fakewriter(void *arg)
        do {
                schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
                udelay(rcu_random(&rand) & 0x3ff);
-               cur_ops->sync();
+               if (cur_ops->cb_barrier != NULL &&
+                   rcu_random(&rand) % (nfakewriters * 8) == 0)
+                       cur_ops->cb_barrier();
+               else
+                       cur_ops->sync();
                rcu_stutter_wait("rcu_torture_fakewriter");
        } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 
@@ -1183,27 +1199,27 @@ rcu_torture_printk(char *page)
        }
        cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
        cnt += sprintf(&page[cnt],
-                      "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
-                      "rtmbe: %d rtbke: %ld rtbre: %ld "
-                      "rtbf: %ld rtb: %ld nt: %ld "
-                      "onoff: %ld/%ld:%ld/%ld "
-                      "barrier: %ld/%ld:%ld",
+                      "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),
+                      atomic_read(&n_rcu_torture_free));
+       cnt += sprintf(&page[cnt], "rtmbe: %d rtbke: %ld rtbre: %ld ",
                       atomic_read(&n_rcu_torture_mberror),
                       n_rcu_torture_boost_ktrerror,
-                      n_rcu_torture_boost_rterror,
+                      n_rcu_torture_boost_rterror);
+       cnt += sprintf(&page[cnt], "rtbf: %ld rtb: %ld nt: %ld ",
                       n_rcu_torture_boost_failure,
                       n_rcu_torture_boosts,
-                      n_rcu_torture_timers,
+                      n_rcu_torture_timers);
+       cnt += sprintf(&page[cnt], "onoff: %ld/%ld:%ld/%ld ",
                       n_online_successes,
                       n_online_attempts,
                       n_offline_successes,
-                      n_offline_attempts,
+                      n_offline_attempts);
+       cnt += sprintf(&page[cnt], "barrier: %ld/%ld:%ld",
                       n_barrier_successes,
                       n_barrier_attempts,
                       n_rcu_torture_barrier_error);
@@ -1445,8 +1461,7 @@ rcu_torture_shutdown(void *arg)
                delta = shutdown_time - jiffies_snap;
                if (verbose)
                        printk(KERN_ALERT "%s" TORTURE_FLAG
-                              "rcu_torture_shutdown task: %lu "
-                              "jiffies remaining\n",
+                              "rcu_torture_shutdown task: %lu jiffies remaining\n",
                               torture_type, delta);
                schedule_timeout_interruptible(delta);
                jiffies_snap = ACCESS_ONCE(jiffies);
@@ -1498,8 +1513,7 @@ rcu_torture_onoff(void *arg)
                        if (cpu_down(cpu) == 0) {
                                if (verbose)
                                        printk(KERN_ALERT "%s" TORTURE_FLAG
-                                              "rcu_torture_onoff task: "
-                                              "offlined %d\n",
+                                              "rcu_torture_onoff task: offlined %d\n",
                                               torture_type, cpu);
                                n_offline_successes++;
                        }
@@ -1512,8 +1526,7 @@ rcu_torture_onoff(void *arg)
                        if (cpu_up(cpu) == 0) {
                                if (verbose)
                                        printk(KERN_ALERT "%s" TORTURE_FLAG
-                                              "rcu_torture_onoff task: "
-                                              "onlined %d\n",
+                                              "rcu_torture_onoff task: onlined %d\n",
                                               torture_type, cpu);
                                n_online_successes++;
                        }
@@ -1631,6 +1644,7 @@ void rcu_torture_barrier_cbf(struct rcu_head *rcu)
 static int rcu_torture_barrier_cbs(void *arg)
 {
        long myid = (long)arg;
+       bool lastphase = 0;
        struct rcu_head rcu;
 
        init_rcu_head_on_stack(&rcu);
@@ -1638,9 +1652,11 @@ static int rcu_torture_barrier_cbs(void *arg)
        set_user_nice(current, 19);
        do {
                wait_event(barrier_cbs_wq[myid],
-                          atomic_read(&barrier_cbs_count) == n_barrier_cbs ||
+                          barrier_phase != lastphase ||
                           kthread_should_stop() ||
                           fullstop != FULLSTOP_DONTSTOP);
+               lastphase = barrier_phase;
+               smp_mb(); /* ensure barrier_phase load before ->call(). */
                if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)
                        break;
                cur_ops->call(&rcu, rcu_torture_barrier_cbf);
@@ -1665,7 +1681,8 @@ static int rcu_torture_barrier(void *arg)
        do {
                atomic_set(&barrier_cbs_invoked, 0);
                atomic_set(&barrier_cbs_count, n_barrier_cbs);
-               /* wake_up() path contains the required barriers. */
+               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,
@@ -1684,7 +1701,7 @@ static int rcu_torture_barrier(void *arg)
                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_cbs");
+       rcutorture_shutdown_absorb("rcu_torture_barrier");
        while (!kthread_should_stop())
                schedule_timeout_interruptible(1);
        return 0;
@@ -1908,8 +1925,8 @@ rcu_torture_init(void)
        static struct rcu_torture_ops *torture_ops[] =
                { &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
                  &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
-                 &srcu_ops, &srcu_sync_ops, &srcu_raw_ops,
-                 &srcu_raw_sync_ops, &srcu_expedited_ops,
+                 &srcu_ops, &srcu_sync_ops, &srcu_expedited_ops,
+                 &srcu_raw_ops, &srcu_raw_sync_ops,
                  &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
 
        mutex_lock(&fullstop_mutex);
@@ -1931,8 +1948,7 @@ rcu_torture_init(void)
                return -EINVAL;
        }
        if (cur_ops->fqs == NULL && fqs_duration != 0) {
-               printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero "
-                                 "fqs_duration, fqs disabled.\n");
+               printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero fqs_duration, fqs disabled.\n");
                fqs_duration = 0;
        }
        if (cur_ops->init)
index 38ecdda3f55f6b3e503cf12e447c1801ae3c2812..f280e542e3e9f531df83b03d1e1fce6cf8ebaaa2 100644 (file)
 
 /* Data structures. */
 
-static struct lock_class_key rcu_node_class[NUM_RCU_LVLS];
-
-#define RCU_STATE_INITIALIZER(structname) { \
-       .level = { &structname##_state.node[0] }, \
-       .levelcnt = { \
-               NUM_RCU_LVL_0,  /* root of hierarchy. */ \
-               NUM_RCU_LVL_1, \
-               NUM_RCU_LVL_2, \
-               NUM_RCU_LVL_3, \
-               NUM_RCU_LVL_4, /* == MAX_RCU_LVLS */ \
-       }, \
+static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
+
+#define RCU_STATE_INITIALIZER(sname, cr) { \
+       .level = { &sname##_state.node[0] }, \
+       .call = cr, \
        .fqs_state = RCU_GP_IDLE, \
        .gpnum = -300, \
        .completed = -300, \
-       .onofflock = __RAW_SPIN_LOCK_UNLOCKED(&structname##_state.onofflock), \
-       .orphan_nxttail = &structname##_state.orphan_nxtlist, \
-       .orphan_donetail = &structname##_state.orphan_donelist, \
-       .fqslock = __RAW_SPIN_LOCK_UNLOCKED(&structname##_state.fqslock), \
-       .n_force_qs = 0, \
-       .n_force_qs_ngp = 0, \
-       .name = #structname, \
+       .onofflock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.onofflock), \
+       .orphan_nxttail = &sname##_state.orphan_nxtlist, \
+       .orphan_donetail = &sname##_state.orphan_donelist, \
+       .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
+       .fqslock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.fqslock), \
+       .name = #sname, \
 }
 
-struct rcu_state rcu_sched_state = RCU_STATE_INITIALIZER(rcu_sched);
+struct rcu_state rcu_sched_state =
+       RCU_STATE_INITIALIZER(rcu_sched, call_rcu_sched);
 DEFINE_PER_CPU(struct rcu_data, rcu_sched_data);
 
-struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh);
+struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh, call_rcu_bh);
 DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
 
 static struct rcu_state *rcu_state;
+LIST_HEAD(rcu_struct_flavors);
+
+/* Increase (but not decrease) the CONFIG_RCU_FANOUT_LEAF at boot time. */
+static int rcu_fanout_leaf = CONFIG_RCU_FANOUT_LEAF;
+module_param(rcu_fanout_leaf, int, 0);
+int rcu_num_lvls __read_mostly = RCU_NUM_LVLS;
+static int num_rcu_lvl[] = {  /* Number of rcu_nodes at specified level. */
+       NUM_RCU_LVL_0,
+       NUM_RCU_LVL_1,
+       NUM_RCU_LVL_2,
+       NUM_RCU_LVL_3,
+       NUM_RCU_LVL_4,
+};
+int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */
 
 /*
  * The rcu_scheduler_active variable transitions from zero to one just
@@ -147,13 +155,6 @@ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp);
 unsigned long rcutorture_testseq;
 unsigned long rcutorture_vernum;
 
-/* State information for rcu_barrier() and friends. */
-
-static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
-static atomic_t rcu_barrier_cpu_count;
-static DEFINE_MUTEX(rcu_barrier_mutex);
-static struct completion rcu_barrier_completion;
-
 /*
  * Return true if an RCU grace period is in progress.  The ACCESS_ONCE()s
  * permit this function to be invoked without holding the root rcu_node
@@ -201,6 +202,7 @@ void rcu_note_context_switch(int cpu)
 {
        trace_rcu_utilization("Start context switch");
        rcu_sched_qs(cpu);
+       rcu_preempt_note_context_switch(cpu);
        trace_rcu_utilization("End context switch");
 }
 EXPORT_SYMBOL_GPL(rcu_note_context_switch);
@@ -357,7 +359,7 @@ static void rcu_idle_enter_common(struct rcu_dynticks *rdtp, long long oldval)
                struct task_struct *idle = idle_task(smp_processor_id());
 
                trace_rcu_dyntick("Error on entry: not idle task", oldval, 0);
-               ftrace_dump(DUMP_ALL);
+               ftrace_dump(DUMP_ORIG);
                WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
                          current->pid, current->comm,
                          idle->pid, idle->comm); /* must be idle task! */
@@ -467,7 +469,7 @@ static void rcu_idle_exit_common(struct rcu_dynticks *rdtp, long long oldval)
 
                trace_rcu_dyntick("Error on exit: not idle task",
                                  oldval, rdtp->dynticks_nesting);
-               ftrace_dump(DUMP_ALL);
+               ftrace_dump(DUMP_ORIG);
                WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
                          current->pid, current->comm,
                          idle->pid, idle->comm); /* must be idle task! */
@@ -584,8 +586,6 @@ void rcu_nmi_exit(void)
        WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
 }
 
-#ifdef CONFIG_PROVE_RCU
-
 /**
  * rcu_is_cpu_idle - see if RCU thinks that the current CPU is idle
  *
@@ -603,7 +603,7 @@ int rcu_is_cpu_idle(void)
 }
 EXPORT_SYMBOL(rcu_is_cpu_idle);
 
-#ifdef CONFIG_HOTPLUG_CPU
+#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU)
 
 /*
  * Is the current CPU online?  Disable preemption to avoid false positives
@@ -644,9 +644,7 @@ bool rcu_lockdep_current_cpu_online(void)
 }
 EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online);
 
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-
-#endif /* #ifdef CONFIG_PROVE_RCU */
+#endif /* #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU) */
 
 /**
  * rcu_is_cpu_rrupt_from_idle - see if idle or immediately interrupted from idle
@@ -732,7 +730,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
        int cpu;
        long delta;
        unsigned long flags;
-       int ndetected;
+       int ndetected = 0;
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        /* Only let one CPU complain about others per time interval. */
@@ -773,7 +771,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
         */
        rnp = rcu_get_root(rsp);
        raw_spin_lock_irqsave(&rnp->lock, flags);
-       ndetected = rcu_print_task_stall(rnp);
+       ndetected += rcu_print_task_stall(rnp);
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
        print_cpu_stall_info_end();
@@ -859,9 +857,10 @@ static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr)
  */
 void rcu_cpu_stall_reset(void)
 {
-       rcu_sched_state.jiffies_stall = jiffies + ULONG_MAX / 2;
-       rcu_bh_state.jiffies_stall = jiffies + ULONG_MAX / 2;
-       rcu_preempt_stall_reset();
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp)
+               rsp->jiffies_stall = jiffies + ULONG_MAX / 2;
 }
 
 static struct notifier_block rcu_panic_block = {
@@ -893,8 +892,9 @@ static void __note_new_gpnum(struct rcu_state *rsp, struct rcu_node *rnp, struct
                if (rnp->qsmask & rdp->grpmask) {
                        rdp->qs_pending = 1;
                        rdp->passed_quiesce = 0;
-               } else
+               } else {
                        rdp->qs_pending = 0;
+               }
                zero_cpu_stall_ticks(rdp);
        }
 }
@@ -935,6 +935,18 @@ check_for_new_grace_period(struct rcu_state *rsp, struct rcu_data *rdp)
        return ret;
 }
 
+/*
+ * Initialize the specified rcu_data structure's callback list to empty.
+ */
+static void init_callback_list(struct rcu_data *rdp)
+{
+       int i;
+
+       rdp->nxtlist = NULL;
+       for (i = 0; i < RCU_NEXT_SIZE; i++)
+               rdp->nxttail[i] = &rdp->nxtlist;
+}
+
 /*
  * Advance this CPU's callbacks, but only if the current grace period
  * has ended.  This may be called only from the CPU to whom the rdp
@@ -1327,8 +1339,6 @@ static void
 rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
                          struct rcu_node *rnp, struct rcu_data *rdp)
 {
-       int i;
-
        /*
         * Orphan the callbacks.  First adjust the counts.  This is safe
         * because ->onofflock excludes _rcu_barrier()'s adoption of
@@ -1339,7 +1349,7 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
                rsp->qlen += rdp->qlen;
                rdp->n_cbs_orphaned += rdp->qlen;
                rdp->qlen_lazy = 0;
-               rdp->qlen = 0;
+               ACCESS_ONCE(rdp->qlen) = 0;
        }
 
        /*
@@ -1368,9 +1378,7 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
        }
 
        /* Finally, initialize the rcu_data structure's list to empty.  */
-       rdp->nxtlist = NULL;
-       for (i = 0; i < RCU_NEXT_SIZE; i++)
-               rdp->nxttail[i] = &rdp->nxtlist;
+       init_callback_list(rdp);
 }
 
 /*
@@ -1504,6 +1512,9 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
        if (need_report & RCU_OFL_TASKS_EXP_GP)
                rcu_report_exp_rnp(rsp, rnp, true);
+       WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL,
+                 "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n",
+                 cpu, rdp->qlen, rdp->nxtlist);
 }
 
 #else /* #ifdef CONFIG_HOTPLUG_CPU */
@@ -1591,7 +1602,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
        }
        smp_mb(); /* List handling before counting for rcu_barrier(). */
        rdp->qlen_lazy -= count_lazy;
-       rdp->qlen -= count;
+       ACCESS_ONCE(rdp->qlen) -= count;
        rdp->n_cbs_invoked += count;
 
        /* Reinstate batch limit if we have worked down the excess. */
@@ -1604,6 +1615,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
                rdp->n_force_qs_snap = rsp->n_force_qs;
        } else if (rdp->qlen < rdp->qlen_last_fqs_check - qhimark)
                rdp->qlen_last_fqs_check = rdp->qlen;
+       WARN_ON_ONCE((rdp->nxtlist == NULL) != (rdp->qlen == 0));
 
        local_irq_restore(flags);
 
@@ -1744,8 +1756,6 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
                break; /* grace period idle or initializing, ignore. */
 
        case RCU_SAVE_DYNTICK:
-               if (RCU_SIGNAL_INIT != RCU_SAVE_DYNTICK)
-                       break; /* So gcc recognizes the dead code. */
 
                raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
 
@@ -1787,9 +1797,10 @@ unlock_fqs_ret:
  * whom the rdp belongs.
  */
 static void
-__rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
+__rcu_process_callbacks(struct rcu_state *rsp)
 {
        unsigned long flags;
+       struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
 
        WARN_ON_ONCE(rdp->beenonline == 0);
 
@@ -1825,11 +1836,11 @@ __rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
  */
 static void rcu_process_callbacks(struct softirq_action *unused)
 {
+       struct rcu_state *rsp;
+
        trace_rcu_utilization("Start RCU core");
-       __rcu_process_callbacks(&rcu_sched_state,
-                               &__get_cpu_var(rcu_sched_data));
-       __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data));
-       rcu_preempt_process_callbacks();
+       for_each_rcu_flavor(rsp)
+               __rcu_process_callbacks(rsp);
        trace_rcu_utilization("End RCU core");
 }
 
@@ -1856,6 +1867,56 @@ static void invoke_rcu_core(void)
        raise_softirq(RCU_SOFTIRQ);
 }
 
+/*
+ * Handle any core-RCU processing required by a call_rcu() invocation.
+ */
+static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
+                           struct rcu_head *head, unsigned long flags)
+{
+       /*
+        * If called from an extended quiescent state, invoke the RCU
+        * core in order to force a re-evaluation of RCU's idleness.
+        */
+       if (rcu_is_cpu_idle() && cpu_online(smp_processor_id()))
+               invoke_rcu_core();
+
+       /* If interrupts were disabled or CPU offline, don't invoke RCU core. */
+       if (irqs_disabled_flags(flags) || cpu_is_offline(smp_processor_id()))
+               return;
+
+       /*
+        * Force the grace period if too many callbacks or too long waiting.
+        * Enforce hysteresis, and don't invoke force_quiescent_state()
+        * if some other CPU has recently done so.  Also, don't bother
+        * invoking force_quiescent_state() if the newly enqueued callback
+        * is the only one waiting for a grace period to complete.
+        */
+       if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
+
+               /* Are we ignoring a completed grace period? */
+               rcu_process_gp_end(rsp, rdp);
+               check_for_new_grace_period(rsp, rdp);
+
+               /* Start a new grace period if one not already started. */
+               if (!rcu_gp_in_progress(rsp)) {
+                       unsigned long nestflag;
+                       struct rcu_node *rnp_root = rcu_get_root(rsp);
+
+                       raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
+                       rcu_start_gp(rsp, nestflag);  /* rlses rnp_root->lock */
+               } else {
+                       /* Give the grace period a kick. */
+                       rdp->blimit = LONG_MAX;
+                       if (rsp->n_force_qs == rdp->n_force_qs_snap &&
+                           *rdp->nxttail[RCU_DONE_TAIL] != head)
+                               force_quiescent_state(rsp, 0);
+                       rdp->n_force_qs_snap = rsp->n_force_qs;
+                       rdp->qlen_last_fqs_check = rdp->qlen;
+               }
+       } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
+               force_quiescent_state(rsp, 1);
+}
+
 static void
 __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
           struct rcu_state *rsp, bool lazy)
@@ -1880,7 +1941,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
        rdp = this_cpu_ptr(rsp->rda);
 
        /* Add the callback to our list. */
-       rdp->qlen++;
+       ACCESS_ONCE(rdp->qlen)++;
        if (lazy)
                rdp->qlen_lazy++;
        else
@@ -1895,43 +1956,8 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
        else
                trace_rcu_callback(rsp->name, head, rdp->qlen_lazy, rdp->qlen);
 
-       /* If interrupts were disabled, don't dive into RCU core. */
-       if (irqs_disabled_flags(flags)) {
-               local_irq_restore(flags);
-               return;
-       }
-
-       /*
-        * Force the grace period if too many callbacks or too long waiting.
-        * Enforce hysteresis, and don't invoke force_quiescent_state()
-        * if some other CPU has recently done so.  Also, don't bother
-        * invoking force_quiescent_state() if the newly enqueued callback
-        * is the only one waiting for a grace period to complete.
-        */
-       if (unlikely(rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
-
-               /* Are we ignoring a completed grace period? */
-               rcu_process_gp_end(rsp, rdp);
-               check_for_new_grace_period(rsp, rdp);
-
-               /* Start a new grace period if one not already started. */
-               if (!rcu_gp_in_progress(rsp)) {
-                       unsigned long nestflag;
-                       struct rcu_node *rnp_root = rcu_get_root(rsp);
-
-                       raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
-                       rcu_start_gp(rsp, nestflag);  /* rlses rnp_root->lock */
-               } else {
-                       /* Give the grace period a kick. */
-                       rdp->blimit = LONG_MAX;
-                       if (rsp->n_force_qs == rdp->n_force_qs_snap &&
-                           *rdp->nxttail[RCU_DONE_TAIL] != head)
-                               force_quiescent_state(rsp, 0);
-                       rdp->n_force_qs_snap = rsp->n_force_qs;
-                       rdp->qlen_last_fqs_check = rdp->qlen;
-               }
-       } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
-               force_quiescent_state(rsp, 1);
+       /* Go handle any RCU core processing required. */
+       __call_rcu_core(rsp, rdp, head, flags);
        local_irq_restore(flags);
 }
 
@@ -1961,28 +1987,16 @@ EXPORT_SYMBOL_GPL(call_rcu_bh);
  * occasionally incorrectly indicate that there are multiple CPUs online
  * when there was in fact only one the whole time, as this just adds
  * some overhead: RCU still operates correctly.
- *
- * Of course, sampling num_online_cpus() with preemption enabled can
- * give erroneous results if there are concurrent CPU-hotplug operations.
- * For example, given a demonic sequence of preemptions in num_online_cpus()
- * and CPU-hotplug operations, there could be two or more CPUs online at
- * all times, but num_online_cpus() might well return one (or even zero).
- *
- * However, all such demonic sequences require at least one CPU-offline
- * operation.  Furthermore, rcu_blocking_is_gp() giving the wrong answer
- * is only a problem if there is an RCU read-side critical section executing
- * throughout.  But RCU-sched and RCU-bh read-side critical sections
- * disable either preemption or bh, which prevents a CPU from going offline.
- * Therefore, the only way that rcu_blocking_is_gp() can incorrectly return
- * that there is only one CPU when in fact there was more than one throughout
- * is when there were no RCU readers in the system.  If there are no
- * RCU readers, the grace period by definition can be of zero length,
- * regardless of the number of online CPUs.
  */
 static inline int rcu_blocking_is_gp(void)
 {
+       int ret;
+
        might_sleep();  /* Check for RCU read-side critical section. */
-       return num_online_cpus() <= 1;
+       preempt_disable();
+       ret = num_online_cpus() <= 1;
+       preempt_enable();
+       return ret;
 }
 
 /**
@@ -2117,9 +2131,9 @@ void synchronize_sched_expedited(void)
                put_online_cpus();
 
                /* No joy, try again later.  Or just synchronize_sched(). */
-               if (trycount++ < 10)
+               if (trycount++ < 10) {
                        udelay(trycount * num_online_cpus());
-               else {
+               else {
                        synchronize_sched();
                        return;
                }
@@ -2240,9 +2254,12 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
  */
 static int rcu_pending(int cpu)
 {
-       return __rcu_pending(&rcu_sched_state, &per_cpu(rcu_sched_data, cpu)) ||
-              __rcu_pending(&rcu_bh_state, &per_cpu(rcu_bh_data, cpu)) ||
-              rcu_preempt_pending(cpu);
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp)
+               if (__rcu_pending(rsp, per_cpu_ptr(rsp->rda, cpu)))
+                       return 1;
+       return 0;
 }
 
 /*
@@ -2252,20 +2269,41 @@ static int rcu_pending(int cpu)
  */
 static int rcu_cpu_has_callbacks(int cpu)
 {
+       struct rcu_state *rsp;
+
        /* RCU callbacks either ready or pending? */
-       return per_cpu(rcu_sched_data, cpu).nxtlist ||
-              per_cpu(rcu_bh_data, cpu).nxtlist ||
-              rcu_preempt_cpu_has_callbacks(cpu);
+       for_each_rcu_flavor(rsp)
+               if (per_cpu_ptr(rsp->rda, cpu)->nxtlist)
+                       return 1;
+       return 0;
+}
+
+/*
+ * Helper function for _rcu_barrier() tracing.  If tracing is disabled,
+ * the compiler is expected to optimize this away.
+ */
+static void _rcu_barrier_trace(struct rcu_state *rsp, char *s,
+                              int cpu, unsigned long done)
+{
+       trace_rcu_barrier(rsp->name, s, cpu,
+                         atomic_read(&rsp->barrier_cpu_count), done);
 }
 
 /*
  * RCU callback function for _rcu_barrier().  If we are last, wake
  * up the task executing _rcu_barrier().
  */
-static void rcu_barrier_callback(struct rcu_head *notused)
+static void rcu_barrier_callback(struct rcu_head *rhp)
 {
-       if (atomic_dec_and_test(&rcu_barrier_cpu_count))
-               complete(&rcu_barrier_completion);
+       struct rcu_data *rdp = container_of(rhp, struct rcu_data, barrier_head);
+       struct rcu_state *rsp = rdp->rsp;
+
+       if (atomic_dec_and_test(&rsp->barrier_cpu_count)) {
+               _rcu_barrier_trace(rsp, "LastCB", -1, rsp->n_barrier_done);
+               complete(&rsp->barrier_completion);
+       } else {
+               _rcu_barrier_trace(rsp, "CB", -1, rsp->n_barrier_done);
+       }
 }
 
 /*
@@ -2273,35 +2311,63 @@ static void rcu_barrier_callback(struct rcu_head *notused)
  */
 static void rcu_barrier_func(void *type)
 {
-       int cpu = smp_processor_id();
-       struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu);
-       void (*call_rcu_func)(struct rcu_head *head,
-                             void (*func)(struct rcu_head *head));
+       struct rcu_state *rsp = type;
+       struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
 
-       atomic_inc(&rcu_barrier_cpu_count);
-       call_rcu_func = type;
-       call_rcu_func(head, rcu_barrier_callback);
+       _rcu_barrier_trace(rsp, "IRQ", -1, rsp->n_barrier_done);
+       atomic_inc(&rsp->barrier_cpu_count);
+       rsp->call(&rdp->barrier_head, rcu_barrier_callback);
 }
 
 /*
  * Orchestrate the specified type of RCU barrier, waiting for all
  * RCU callbacks of the specified type to complete.
  */
-static void _rcu_barrier(struct rcu_state *rsp,
-                        void (*call_rcu_func)(struct rcu_head *head,
-                                              void (*func)(struct rcu_head *head)))
+static void _rcu_barrier(struct rcu_state *rsp)
 {
        int cpu;
        unsigned long flags;
        struct rcu_data *rdp;
-       struct rcu_head rh;
+       struct rcu_data rd;
+       unsigned long snap = ACCESS_ONCE(rsp->n_barrier_done);
+       unsigned long snap_done;
 
-       init_rcu_head_on_stack(&rh);
+       init_rcu_head_on_stack(&rd.barrier_head);
+       _rcu_barrier_trace(rsp, "Begin", -1, snap);
 
        /* Take mutex to serialize concurrent rcu_barrier() requests. */
-       mutex_lock(&rcu_barrier_mutex);
+       mutex_lock(&rsp->barrier_mutex);
+
+       /*
+        * Ensure that all prior references, including to ->n_barrier_done,
+        * are ordered before the _rcu_barrier() machinery.
+        */
+       smp_mb();  /* See above block comment. */
+
+       /*
+        * Recheck ->n_barrier_done to see if others did our work for us.
+        * This means checking ->n_barrier_done for an even-to-odd-to-even
+        * transition.  The "if" expression below therefore rounds the old
+        * value up to the next even number and adds two before comparing.
+        */
+       snap_done = ACCESS_ONCE(rsp->n_barrier_done);
+       _rcu_barrier_trace(rsp, "Check", -1, snap_done);
+       if (ULONG_CMP_GE(snap_done, ((snap + 1) & ~0x1) + 2)) {
+               _rcu_barrier_trace(rsp, "EarlyExit", -1, snap_done);
+               smp_mb(); /* caller's subsequent code after above check. */
+               mutex_unlock(&rsp->barrier_mutex);
+               return;
+       }
 
-       smp_mb();  /* Prevent any prior operations from leaking in. */
+       /*
+        * Increment ->n_barrier_done to avoid duplicate work.  Use
+        * ACCESS_ONCE() to prevent the compiler from speculating
+        * the increment to precede the early-exit check.
+        */
+       ACCESS_ONCE(rsp->n_barrier_done)++;
+       WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 1);
+       _rcu_barrier_trace(rsp, "Inc1", -1, rsp->n_barrier_done);
+       smp_mb(); /* Order ->n_barrier_done increment with below mechanism. */
 
        /*
         * Initialize the count to one rather than to zero in order to
@@ -2320,8 +2386,8 @@ static void _rcu_barrier(struct rcu_state *rsp,
         * 6.   Both rcu_barrier_callback() callbacks are invoked, awakening
         *      us -- but before CPU 1's orphaned callbacks are invoked!!!
         */
-       init_completion(&rcu_barrier_completion);
-       atomic_set(&rcu_barrier_cpu_count, 1);
+       init_completion(&rsp->barrier_completion);
+       atomic_set(&rsp->barrier_cpu_count, 1);
        raw_spin_lock_irqsave(&rsp->onofflock, flags);
        rsp->rcu_barrier_in_progress = current;
        raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
@@ -2337,14 +2403,19 @@ static void _rcu_barrier(struct rcu_state *rsp,
                preempt_disable();
                rdp = per_cpu_ptr(rsp->rda, cpu);
                if (cpu_is_offline(cpu)) {
+                       _rcu_barrier_trace(rsp, "Offline", cpu,
+                                          rsp->n_barrier_done);
                        preempt_enable();
                        while (cpu_is_offline(cpu) && ACCESS_ONCE(rdp->qlen))
                                schedule_timeout_interruptible(1);
                } else if (ACCESS_ONCE(rdp->qlen)) {
-                       smp_call_function_single(cpu, rcu_barrier_func,
-                                                (void *)call_rcu_func, 1);
+                       _rcu_barrier_trace(rsp, "OnlineQ", cpu,
+                                          rsp->n_barrier_done);
+                       smp_call_function_single(cpu, rcu_barrier_func, rsp, 1);
                        preempt_enable();
                } else {
+                       _rcu_barrier_trace(rsp, "OnlineNQ", cpu,
+                                          rsp->n_barrier_done);
                        preempt_enable();
                }
        }
@@ -2361,24 +2432,32 @@ static void _rcu_barrier(struct rcu_state *rsp,
        rcu_adopt_orphan_cbs(rsp);
        rsp->rcu_barrier_in_progress = NULL;
        raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
-       atomic_inc(&rcu_barrier_cpu_count);
+       atomic_inc(&rsp->barrier_cpu_count);
        smp_mb__after_atomic_inc(); /* Ensure atomic_inc() before callback. */
-       call_rcu_func(&rh, rcu_barrier_callback);
+       rd.rsp = rsp;
+       rsp->call(&rd.barrier_head, rcu_barrier_callback);
 
        /*
         * Now that we have an rcu_barrier_callback() callback on each
         * CPU, and thus each counted, remove the initial count.
         */
-       if (atomic_dec_and_test(&rcu_barrier_cpu_count))
-               complete(&rcu_barrier_completion);
+       if (atomic_dec_and_test(&rsp->barrier_cpu_count))
+               complete(&rsp->barrier_completion);
+
+       /* Increment ->n_barrier_done to prevent duplicate work. */
+       smp_mb(); /* Keep increment after above mechanism. */
+       ACCESS_ONCE(rsp->n_barrier_done)++;
+       WARN_ON_ONCE((rsp->n_barrier_done & 0x1) != 0);
+       _rcu_barrier_trace(rsp, "Inc2", -1, rsp->n_barrier_done);
+       smp_mb(); /* Keep increment before caller's subsequent code. */
 
        /* Wait for all rcu_barrier_callback() callbacks to be invoked. */
-       wait_for_completion(&rcu_barrier_completion);
+       wait_for_completion(&rsp->barrier_completion);
 
        /* Other rcu_barrier() invocations can now safely proceed. */
-       mutex_unlock(&rcu_barrier_mutex);
+       mutex_unlock(&rsp->barrier_mutex);
 
-       destroy_rcu_head_on_stack(&rh);
+       destroy_rcu_head_on_stack(&rd.barrier_head);
 }
 
 /**
@@ -2386,7 +2465,7 @@ static void _rcu_barrier(struct rcu_state *rsp,
  */
 void rcu_barrier_bh(void)
 {
-       _rcu_barrier(&rcu_bh_state, call_rcu_bh);
+       _rcu_barrier(&rcu_bh_state);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier_bh);
 
@@ -2395,7 +2474,7 @@ EXPORT_SYMBOL_GPL(rcu_barrier_bh);
  */
 void rcu_barrier_sched(void)
 {
-       _rcu_barrier(&rcu_sched_state, call_rcu_sched);
+       _rcu_barrier(&rcu_sched_state);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier_sched);
 
@@ -2406,18 +2485,15 @@ static void __init
 rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
 {
        unsigned long flags;
-       int i;
        struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        /* Set up local state, ensuring consistent view of global state. */
        raw_spin_lock_irqsave(&rnp->lock, flags);
        rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo);
-       rdp->nxtlist = NULL;
-       for (i = 0; i < RCU_NEXT_SIZE; i++)
-               rdp->nxttail[i] = &rdp->nxtlist;
+       init_callback_list(rdp);
        rdp->qlen_lazy = 0;
-       rdp->qlen = 0;
+       ACCESS_ONCE(rdp->qlen) = 0;
        rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
        WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
        WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);
@@ -2491,9 +2567,11 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
 
 static void __cpuinit rcu_prepare_cpu(int cpu)
 {
-       rcu_init_percpu_data(cpu, &rcu_sched_state, 0);
-       rcu_init_percpu_data(cpu, &rcu_bh_state, 0);
-       rcu_preempt_init_percpu_data(cpu);
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp)
+               rcu_init_percpu_data(cpu, rsp,
+                                    strcmp(rsp->name, "rcu_preempt") == 0);
 }
 
 /*
@@ -2505,6 +2583,7 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
        long cpu = (long)hcpu;
        struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
        struct rcu_node *rnp = rdp->mynode;
+       struct rcu_state *rsp;
 
        trace_rcu_utilization("Start CPU hotplug");
        switch (action) {
@@ -2529,18 +2608,16 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
                 * touch any data without introducing corruption. We send the
                 * dying CPU's callbacks to an arbitrarily chosen online CPU.
                 */
-               rcu_cleanup_dying_cpu(&rcu_bh_state);
-               rcu_cleanup_dying_cpu(&rcu_sched_state);
-               rcu_preempt_cleanup_dying_cpu();
+               for_each_rcu_flavor(rsp)
+                       rcu_cleanup_dying_cpu(rsp);
                rcu_cleanup_after_idle(cpu);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
-               rcu_cleanup_dead_cpu(cpu, &rcu_bh_state);
-               rcu_cleanup_dead_cpu(cpu, &rcu_sched_state);
-               rcu_preempt_cleanup_dead_cpu(cpu);
+               for_each_rcu_flavor(rsp)
+                       rcu_cleanup_dead_cpu(cpu, rsp);
                break;
        default:
                break;
@@ -2573,9 +2650,9 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
 {
        int i;
 
-       for (i = NUM_RCU_LVLS - 1; i > 0; i--)
+       for (i = rcu_num_lvls - 1; i > 0; i--)
                rsp->levelspread[i] = CONFIG_RCU_FANOUT;
-       rsp->levelspread[0] = CONFIG_RCU_FANOUT_LEAF;
+       rsp->levelspread[0] = rcu_fanout_leaf;
 }
 #else /* #ifdef CONFIG_RCU_FANOUT_EXACT */
 static void __init rcu_init_levelspread(struct rcu_state *rsp)
@@ -2585,7 +2662,7 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
        int i;
 
        cprv = NR_CPUS;
-       for (i = NUM_RCU_LVLS - 1; i >= 0; i--) {
+       for (i = rcu_num_lvls - 1; i >= 0; i--) {
                ccur = rsp->levelcnt[i];
                rsp->levelspread[i] = (cprv + ccur - 1) / ccur;
                cprv = ccur;
@@ -2612,13 +2689,15 @@ static void __init rcu_init_one(struct rcu_state *rsp,
 
        /* Initialize the level-tracking arrays. */
 
-       for (i = 1; i < NUM_RCU_LVLS; i++)
+       for (i = 0; i < rcu_num_lvls; i++)
+               rsp->levelcnt[i] = num_rcu_lvl[i];
+       for (i = 1; i < rcu_num_lvls; i++)
                rsp->level[i] = rsp->level[i - 1] + rsp->levelcnt[i - 1];
        rcu_init_levelspread(rsp);
 
        /* Initialize the elements themselves, starting from the leaves. */
 
-       for (i = NUM_RCU_LVLS - 1; i >= 0; i--) {
+       for (i = rcu_num_lvls - 1; i >= 0; i--) {
                cpustride *= rsp->levelspread[i];
                rnp = rsp->level[i];
                for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) {
@@ -2648,13 +2727,74 @@ static void __init rcu_init_one(struct rcu_state *rsp,
        }
 
        rsp->rda = rda;
-       rnp = rsp->level[NUM_RCU_LVLS - 1];
+       rnp = rsp->level[rcu_num_lvls - 1];
        for_each_possible_cpu(i) {
                while (i > rnp->grphi)
                        rnp++;
                per_cpu_ptr(rsp->rda, i)->mynode = rnp;
                rcu_boot_init_percpu_data(i, rsp);
        }
+       list_add(&rsp->flavors, &rcu_struct_flavors);
+}
+
+/*
+ * Compute the rcu_node tree geometry from kernel parameters.  This cannot
+ * replace the definitions in rcutree.h because those are needed to size
+ * the ->node array in the rcu_state structure.
+ */
+static void __init rcu_init_geometry(void)
+{
+       int i;
+       int j;
+       int n = nr_cpu_ids;
+       int rcu_capacity[MAX_RCU_LVLS + 1];
+
+       /* If the compile-time values are accurate, just leave. */
+       if (rcu_fanout_leaf == CONFIG_RCU_FANOUT_LEAF)
+               return;
+
+       /*
+        * Compute number of nodes that can be handled an rcu_node tree
+        * with the given number of levels.  Setting rcu_capacity[0] makes
+        * some of the arithmetic easier.
+        */
+       rcu_capacity[0] = 1;
+       rcu_capacity[1] = rcu_fanout_leaf;
+       for (i = 2; i <= MAX_RCU_LVLS; i++)
+               rcu_capacity[i] = rcu_capacity[i - 1] * CONFIG_RCU_FANOUT;
+
+       /*
+        * The boot-time rcu_fanout_leaf parameter is only permitted
+        * to increase the leaf-level fanout, not decrease it.  Of course,
+        * the leaf-level fanout cannot exceed the number of bits in
+        * the rcu_node masks.  Finally, the tree must be able to accommodate
+        * the configured number of CPUs.  Complain and fall back to the
+        * compile-time values if these limits are exceeded.
+        */
+       if (rcu_fanout_leaf < CONFIG_RCU_FANOUT_LEAF ||
+           rcu_fanout_leaf > sizeof(unsigned long) * 8 ||
+           n > rcu_capacity[MAX_RCU_LVLS]) {
+               WARN_ON(1);
+               return;
+       }
+
+       /* Calculate the number of rcu_nodes at each level of the tree. */
+       for (i = 1; i <= MAX_RCU_LVLS; i++)
+               if (n <= rcu_capacity[i]) {
+                       for (j = 0; j <= i; j++)
+                               num_rcu_lvl[j] =
+                                       DIV_ROUND_UP(n, rcu_capacity[i - j]);
+                       rcu_num_lvls = i;
+                       for (j = i + 1; j <= MAX_RCU_LVLS; j++)
+                               num_rcu_lvl[j] = 0;
+                       break;
+               }
+
+       /* Calculate the total number of rcu_node structures. */
+       rcu_num_nodes = 0;
+       for (i = 0; i <= MAX_RCU_LVLS; i++)
+               rcu_num_nodes += num_rcu_lvl[i];
+       rcu_num_nodes -= n;
 }
 
 void __init rcu_init(void)
@@ -2662,6 +2802,7 @@ void __init rcu_init(void)
        int cpu;
 
        rcu_bootup_announce();
+       rcu_init_geometry();
        rcu_init_one(&rcu_sched_state, &rcu_sched_data);
        rcu_init_one(&rcu_bh_state, &rcu_bh_data);
        __rcu_init_preempt();
index ea056495783e1a09c482802bd2e66d0c863c8a35..4d29169f212468bdc6f8dd17311ecf8bdd6850a8 100644 (file)
 #define RCU_FANOUT_4         (RCU_FANOUT_3 * CONFIG_RCU_FANOUT)
 
 #if NR_CPUS <= RCU_FANOUT_1
-#  define NUM_RCU_LVLS       1
+#  define RCU_NUM_LVLS       1
 #  define NUM_RCU_LVL_0              1
 #  define NUM_RCU_LVL_1              (NR_CPUS)
 #  define NUM_RCU_LVL_2              0
 #  define NUM_RCU_LVL_3              0
 #  define NUM_RCU_LVL_4              0
 #elif NR_CPUS <= RCU_FANOUT_2
-#  define NUM_RCU_LVLS       2
+#  define RCU_NUM_LVLS       2
 #  define NUM_RCU_LVL_0              1
 #  define NUM_RCU_LVL_1              DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)
 #  define NUM_RCU_LVL_2              (NR_CPUS)
 #  define NUM_RCU_LVL_3              0
 #  define NUM_RCU_LVL_4              0
 #elif NR_CPUS <= RCU_FANOUT_3
-#  define NUM_RCU_LVLS       3
+#  define RCU_NUM_LVLS       3
 #  define NUM_RCU_LVL_0              1
 #  define NUM_RCU_LVL_1              DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)
 #  define NUM_RCU_LVL_2              DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_1)
 #  define NUM_RCU_LVL_3              (NR_CPUS)
 #  define NUM_RCU_LVL_4              0
 #elif NR_CPUS <= RCU_FANOUT_4
-#  define NUM_RCU_LVLS       4
+#  define RCU_NUM_LVLS       4
 #  define NUM_RCU_LVL_0              1
 #  define NUM_RCU_LVL_1              DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_3)
 #  define NUM_RCU_LVL_2              DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_2)
@@ -76,6 +76,9 @@
 #define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3 + NUM_RCU_LVL_4)
 #define NUM_RCU_NODES (RCU_SUM - NR_CPUS)
 
+extern int rcu_num_lvls;
+extern int rcu_num_nodes;
+
 /*
  * Dynticks per-CPU state.
  */
@@ -97,6 +100,7 @@ struct rcu_dynticks {
                                    /* # times non-lazy CBs posted to CPU. */
        unsigned long nonlazy_posted_snap;
                                    /* idle-period nonlazy_posted snapshot. */
+       int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
 #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
 };
 
@@ -206,7 +210,7 @@ struct rcu_node {
  */
 #define rcu_for_each_node_breadth_first(rsp, rnp) \
        for ((rnp) = &(rsp)->node[0]; \
-            (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)
+            (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++)
 
 /*
  * Do a breadth-first scan of the non-leaf rcu_node structures for the
@@ -215,7 +219,7 @@ struct rcu_node {
  */
 #define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \
        for ((rnp) = &(rsp)->node[0]; \
-            (rnp) < (rsp)->level[NUM_RCU_LVLS - 1]; (rnp)++)
+            (rnp) < (rsp)->level[rcu_num_lvls - 1]; (rnp)++)
 
 /*
  * Scan the leaves of the rcu_node hierarchy for the specified rcu_state
@@ -224,8 +228,8 @@ struct rcu_node {
  * It is still a leaf node, even if it is also the root node.
  */
 #define rcu_for_each_leaf_node(rsp, rnp) \
-       for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \
-            (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)
+       for ((rnp) = (rsp)->level[rcu_num_lvls - 1]; \
+            (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++)
 
 /* Index values for nxttail array in struct rcu_data. */
 #define RCU_DONE_TAIL          0       /* Also RCU_WAIT head. */
@@ -311,6 +315,9 @@ struct rcu_data {
        unsigned long n_rp_need_fqs;
        unsigned long n_rp_need_nothing;
 
+       /* 6) _rcu_barrier() callback. */
+       struct rcu_head barrier_head;
+
        int cpu;
        struct rcu_state *rsp;
 };
@@ -357,10 +364,12 @@ do {                                                                      \
  */
 struct rcu_state {
        struct rcu_node node[NUM_RCU_NODES];    /* Hierarchy. */
-       struct rcu_node *level[NUM_RCU_LVLS];   /* Hierarchy levels. */
+       struct rcu_node *level[RCU_NUM_LVLS];   /* Hierarchy levels. */
        u32 levelcnt[MAX_RCU_LVLS + 1];         /* # nodes in each level. */
-       u8 levelspread[NUM_RCU_LVLS];           /* kids/node in each level. */
+       u8 levelspread[RCU_NUM_LVLS];           /* kids/node in each level. */
        struct rcu_data __percpu *rda;          /* pointer of percu rcu_data. */
+       void (*call)(struct rcu_head *head,     /* call_rcu() flavor. */
+                    void (*func)(struct rcu_head *head));
 
        /* The following fields are guarded by the root rcu_node's lock. */
 
@@ -392,6 +401,11 @@ struct rcu_state {
        struct task_struct *rcu_barrier_in_progress;
                                                /* Task doing rcu_barrier(), */
                                                /*  or NULL if no barrier. */
+       struct mutex barrier_mutex;             /* Guards barrier fields. */
+       atomic_t barrier_cpu_count;             /* # CPUs waiting on. */
+       struct completion barrier_completion;   /* Wake at barrier end. */
+       unsigned long n_barrier_done;           /* ++ at start and end of */
+                                               /*  _rcu_barrier(). */
        raw_spinlock_t fqslock;                 /* Only one task forcing */
                                                /*  quiescent states. */
        unsigned long jiffies_force_qs;         /* Time at which to invoke */
@@ -409,8 +423,13 @@ struct rcu_state {
        unsigned long gp_max;                   /* Maximum GP duration in */
                                                /*  jiffies. */
        char *name;                             /* Name of structure. */
+       struct list_head flavors;               /* List of RCU flavors. */
 };
 
+extern struct list_head rcu_struct_flavors;
+#define for_each_rcu_flavor(rsp) \
+       list_for_each_entry((rsp), &rcu_struct_flavors, flavors)
+
 /* Return values for rcu_preempt_offline_tasks(). */
 
 #define RCU_OFL_TASKS_NORM_GP  0x1             /* Tasks blocking normal */
@@ -444,6 +463,7 @@ DECLARE_PER_CPU(char, rcu_cpu_has_work);
 /* Forward declarations for rcutree_plugin.h */
 static void rcu_bootup_announce(void);
 long rcu_batches_completed(void);
+static void rcu_preempt_note_context_switch(int cpu);
 static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp);
 #ifdef CONFIG_HOTPLUG_CPU
 static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp,
@@ -452,25 +472,18 @@ static void rcu_stop_cpu_kthread(int cpu);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 static void rcu_print_detail_task_stall(struct rcu_state *rsp);
 static int rcu_print_task_stall(struct rcu_node *rnp);
-static void rcu_preempt_stall_reset(void);
 static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
 #ifdef CONFIG_HOTPLUG_CPU
 static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
                                     struct rcu_node *rnp,
                                     struct rcu_data *rdp);
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
-static void rcu_preempt_cleanup_dead_cpu(int cpu);
 static void rcu_preempt_check_callbacks(int cpu);
-static void rcu_preempt_process_callbacks(void);
 void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
 #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU)
 static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
                               bool wake);
 #endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */
-static int rcu_preempt_pending(int cpu);
-static int rcu_preempt_cpu_has_callbacks(int cpu);
-static void __cpuinit rcu_preempt_init_percpu_data(int cpu);
-static void rcu_preempt_cleanup_dying_cpu(void);
 static void __init __rcu_init_preempt(void);
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
 static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
index 5271a020887e6ea515aa29c9f52f9f612d9056ac..7f3244c0df014a7673831159ae1dbc25ceff55c8 100644 (file)
@@ -68,17 +68,21 @@ static void __init rcu_bootup_announce_oddness(void)
        printk(KERN_INFO "\tAdditional per-CPU info printed with stalls.\n");
 #endif
 #if NUM_RCU_LVL_4 != 0
-       printk(KERN_INFO "\tExperimental four-level hierarchy is enabled.\n");
+       printk(KERN_INFO "\tFour-level hierarchy is enabled.\n");
 #endif
+       if (rcu_fanout_leaf != CONFIG_RCU_FANOUT_LEAF)
+               printk(KERN_INFO "\tExperimental boot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);
+       if (nr_cpu_ids != NR_CPUS)
+               printk(KERN_INFO "\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
 }
 
 #ifdef CONFIG_TREE_PREEMPT_RCU
 
-struct rcu_state rcu_preempt_state = RCU_STATE_INITIALIZER(rcu_preempt);
+struct rcu_state rcu_preempt_state =
+       RCU_STATE_INITIALIZER(rcu_preempt, call_rcu);
 DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data);
 static struct rcu_state *rcu_state = &rcu_preempt_state;
 
-static void rcu_read_unlock_special(struct task_struct *t);
 static int rcu_preempted_readers_exp(struct rcu_node *rnp);
 
 /*
@@ -153,7 +157,7 @@ static void rcu_preempt_qs(int cpu)
  *
  * Caller must disable preemption.
  */
-void rcu_preempt_note_context_switch(void)
+static void rcu_preempt_note_context_switch(int cpu)
 {
        struct task_struct *t = current;
        unsigned long flags;
@@ -164,7 +168,7 @@ void rcu_preempt_note_context_switch(void)
            (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
 
                /* Possibly blocking in an RCU read-side critical section. */
-               rdp = __this_cpu_ptr(rcu_preempt_state.rda);
+               rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu);
                rnp = rdp->mynode;
                raw_spin_lock_irqsave(&rnp->lock, flags);
                t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
@@ -228,22 +232,10 @@ void rcu_preempt_note_context_switch(void)
         * means that we continue to block the current grace period.
         */
        local_irq_save(flags);
-       rcu_preempt_qs(smp_processor_id());
+       rcu_preempt_qs(cpu);
        local_irq_restore(flags);
 }
 
-/*
- * Tree-preemptible RCU implementation for rcu_read_lock().
- * Just increment ->rcu_read_lock_nesting, shared state will be updated
- * if we block.
- */
-void __rcu_read_lock(void)
-{
-       current->rcu_read_lock_nesting++;
-       barrier();  /* needed if we ever invoke rcu_read_lock in rcutree.c */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_lock);
-
 /*
  * Check for preempted RCU readers blocking the current grace period
  * for the specified rcu_node structure.  If the caller needs a reliable
@@ -310,7 +302,7 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t,
  * notify RCU core processing or task having blocked during the RCU
  * read-side critical section.
  */
-static noinline void rcu_read_unlock_special(struct task_struct *t)
+void rcu_read_unlock_special(struct task_struct *t)
 {
        int empty;
        int empty_exp;
@@ -398,8 +390,9 @@ static noinline void rcu_read_unlock_special(struct task_struct *t)
                                                         rnp->grphi,
                                                         !!rnp->gp_tasks);
                        rcu_report_unblock_qs_rnp(rnp, flags);
-               } else
+               } else {
                        raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               }
 
 #ifdef CONFIG_RCU_BOOST
                /* Unboost if we were boosted. */
@@ -418,38 +411,6 @@ static noinline void rcu_read_unlock_special(struct task_struct *t)
        }
 }
 
-/*
- * Tree-preemptible RCU implementation for rcu_read_unlock().
- * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
- * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
- * invoke rcu_read_unlock_special() to clean up after a context switch
- * in an RCU read-side critical section and other special cases.
- */
-void __rcu_read_unlock(void)
-{
-       struct task_struct *t = current;
-
-       if (t->rcu_read_lock_nesting != 1)
-               --t->rcu_read_lock_nesting;
-       else {
-               barrier();  /* critical section before exit code. */
-               t->rcu_read_lock_nesting = INT_MIN;
-               barrier();  /* assign before ->rcu_read_unlock_special load */
-               if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
-                       rcu_read_unlock_special(t);
-               barrier();  /* ->rcu_read_unlock_special load before assign */
-               t->rcu_read_lock_nesting = 0;
-       }
-#ifdef CONFIG_PROVE_LOCKING
-       {
-               int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
-
-               WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
-       }
-#endif /* #ifdef CONFIG_PROVE_LOCKING */
-}
-EXPORT_SYMBOL_GPL(__rcu_read_unlock);
-
 #ifdef CONFIG_RCU_CPU_STALL_VERBOSE
 
 /*
@@ -539,16 +500,6 @@ static int rcu_print_task_stall(struct rcu_node *rnp)
        return ndetected;
 }
 
-/*
- * Suppress preemptible RCU's CPU stall warnings by pushing the
- * time of the next stall-warning message comfortably far into the
- * future.
- */
-static void rcu_preempt_stall_reset(void)
-{
-       rcu_preempt_state.jiffies_stall = jiffies + ULONG_MAX / 2;
-}
-
 /*
  * Check that the list of blocked tasks for the newly completed grace
  * period is in fact empty.  It is a serious bug to complete a grace
@@ -649,14 +600,6 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
-/*
- * Do CPU-offline processing for preemptible RCU.
- */
-static void rcu_preempt_cleanup_dead_cpu(int cpu)
-{
-       rcu_cleanup_dead_cpu(cpu, &rcu_preempt_state);
-}
-
 /*
  * Check for a quiescent state from the current CPU.  When a task blocks,
  * the task is recorded in the corresponding CPU's rcu_node structure,
@@ -677,15 +620,6 @@ static void rcu_preempt_check_callbacks(int cpu)
                t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
 }
 
-/*
- * Process callbacks for preemptible RCU.
- */
-static void rcu_preempt_process_callbacks(void)
-{
-       __rcu_process_callbacks(&rcu_preempt_state,
-                               &__get_cpu_var(rcu_preempt_data));
-}
-
 #ifdef CONFIG_RCU_BOOST
 
 static void rcu_preempt_do_callbacks(void)
@@ -824,9 +758,9 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp)
        int must_wait = 0;
 
        raw_spin_lock_irqsave(&rnp->lock, flags);
-       if (list_empty(&rnp->blkd_tasks))
+       if (list_empty(&rnp->blkd_tasks)) {
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
-       else {
+       else {
                rnp->exp_tasks = rnp->blkd_tasks.next;
                rcu_initiate_boost(rnp, flags);  /* releases rnp->lock */
                must_wait = 1;
@@ -870,9 +804,9 @@ void synchronize_rcu_expedited(void)
         * expedited grace period for us, just leave.
         */
        while (!mutex_trylock(&sync_rcu_preempt_exp_mutex)) {
-               if (trycount++ < 10)
+               if (trycount++ < 10) {
                        udelay(trycount * num_online_cpus());
-               else {
+               else {
                        synchronize_rcu();
                        return;
                }
@@ -917,50 +851,15 @@ mb_ret:
 }
 EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
 
-/*
- * Check to see if there is any immediate preemptible-RCU-related work
- * to be done.
- */
-static int rcu_preempt_pending(int cpu)
-{
-       return __rcu_pending(&rcu_preempt_state,
-                            &per_cpu(rcu_preempt_data, cpu));
-}
-
-/*
- * Does preemptible RCU have callbacks on this CPU?
- */
-static int rcu_preempt_cpu_has_callbacks(int cpu)
-{
-       return !!per_cpu(rcu_preempt_data, cpu).nxtlist;
-}
-
 /**
  * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete.
  */
 void rcu_barrier(void)
 {
-       _rcu_barrier(&rcu_preempt_state, call_rcu);
+       _rcu_barrier(&rcu_preempt_state);
 }
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
-/*
- * Initialize preemptible RCU's per-CPU data.
- */
-static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
-{
-       rcu_init_percpu_data(cpu, &rcu_preempt_state, 1);
-}
-
-/*
- * Move preemptible RCU's callbacks from dying CPU to other online CPU
- * and record a quiescent state.
- */
-static void rcu_preempt_cleanup_dying_cpu(void)
-{
-       rcu_cleanup_dying_cpu(&rcu_preempt_state);
-}
-
 /*
  * Initialize preemptible RCU's state structures.
  */
@@ -1001,6 +900,14 @@ void rcu_force_quiescent_state(void)
 }
 EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
 
+/*
+ * Because preemptible RCU does not exist, we never have to check for
+ * CPUs being in quiescent states.
+ */
+static void rcu_preempt_note_context_switch(int cpu)
+{
+}
+
 /*
  * Because preemptible RCU does not exist, there are never any preempted
  * RCU readers.
@@ -1037,14 +944,6 @@ static int rcu_print_task_stall(struct rcu_node *rnp)
        return 0;
 }
 
-/*
- * Because preemptible RCU does not exist, there is no need to suppress
- * its CPU stall warnings.
- */
-static void rcu_preempt_stall_reset(void)
-{
-}
-
 /*
  * Because there is no preemptible RCU, there can be no readers blocked,
  * so there is no need to check for blocked tasks.  So check only for
@@ -1072,14 +971,6 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
-/*
- * Because preemptible RCU does not exist, it never needs CPU-offline
- * processing.
- */
-static void rcu_preempt_cleanup_dead_cpu(int cpu)
-{
-}
-
 /*
  * Because preemptible RCU does not exist, it never has any callbacks
  * to check.
@@ -1088,14 +979,6 @@ static void rcu_preempt_check_callbacks(int cpu)
 {
 }
 
-/*
- * Because preemptible RCU does not exist, it never has any callbacks
- * to process.
- */
-static void rcu_preempt_process_callbacks(void)
-{
-}
-
 /*
  * Queue an RCU callback for lazy invocation after a grace period.
  * This will likely be later named something like "call_rcu_lazy()",
@@ -1136,22 +1019,6 @@ static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
 
 #endif /* #ifdef CONFIG_HOTPLUG_CPU */
 
-/*
- * Because preemptible RCU does not exist, it never has any work to do.
- */
-static int rcu_preempt_pending(int cpu)
-{
-       return 0;
-}
-
-/*
- * Because preemptible RCU does not exist, it never has callbacks
- */
-static int rcu_preempt_cpu_has_callbacks(int cpu)
-{
-       return 0;
-}
-
 /*
  * Because preemptible RCU does not exist, rcu_barrier() is just
  * another name for rcu_barrier_sched().
@@ -1162,21 +1029,6 @@ void rcu_barrier(void)
 }
 EXPORT_SYMBOL_GPL(rcu_barrier);
 
-/*
- * Because preemptible RCU does not exist, there is no per-CPU
- * data to initialize.
- */
-static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
-{
-}
-
-/*
- * Because there is no preemptible RCU, there is no cleanup to do.
- */
-static void rcu_preempt_cleanup_dying_cpu(void)
-{
-}
-
 /*
  * Because preemptible RCU does not exist, it need not be initialized.
  */
@@ -1960,9 +1812,11 @@ static void rcu_idle_count_callbacks_posted(void)
  */
 #define RCU_IDLE_FLUSHES 5             /* Number of dyntick-idle tries. */
 #define RCU_IDLE_OPT_FLUSHES 3         /* Optional dyntick-idle tries. */
-#define RCU_IDLE_GP_DELAY 6            /* Roughly one grace period. */
+#define RCU_IDLE_GP_DELAY 4            /* Roughly one grace period. */
 #define RCU_IDLE_LAZY_GP_DELAY (6 * HZ)        /* Roughly six seconds. */
 
+extern int tick_nohz_enabled;
+
 /*
  * Does the specified flavor of RCU have non-lazy callbacks pending on
  * the specified CPU?  Both RCU flavor and CPU are specified by the
@@ -2039,10 +1893,13 @@ int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
                return 1;
        }
        /* Set up for the possibility that RCU will post a timer. */
-       if (rcu_cpu_has_nonlazy_callbacks(cpu))
-               *delta_jiffies = RCU_IDLE_GP_DELAY;
-       else
-               *delta_jiffies = RCU_IDLE_LAZY_GP_DELAY;
+       if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
+               *delta_jiffies = round_up(RCU_IDLE_GP_DELAY + jiffies,
+                                         RCU_IDLE_GP_DELAY) - jiffies;
+       } else {
+               *delta_jiffies = jiffies + RCU_IDLE_LAZY_GP_DELAY;
+               *delta_jiffies = round_jiffies(*delta_jiffies) - jiffies;
+       }
        return 0;
 }
 
@@ -2101,6 +1958,7 @@ static void rcu_cleanup_after_idle(int cpu)
 
        del_timer(&rdtp->idle_gp_timer);
        trace_rcu_prep_idle("Cleanup after idle");
+       rdtp->tick_nohz_enabled_snap = ACCESS_ONCE(tick_nohz_enabled);
 }
 
 /*
@@ -2126,6 +1984,18 @@ static void rcu_prepare_for_idle(int cpu)
 {
        struct timer_list *tp;
        struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
+       int tne;
+
+       /* Handle nohz enablement switches conservatively. */
+       tne = ACCESS_ONCE(tick_nohz_enabled);
+       if (tne != rdtp->tick_nohz_enabled_snap) {
+               if (rcu_cpu_has_callbacks(cpu))
+                       invoke_rcu_core(); /* force nohz to see update. */
+               rdtp->tick_nohz_enabled_snap = tne;
+               return;
+       }
+       if (!tne)
+               return;
 
        /*
         * If this is an idle re-entry, for example, due to use of
@@ -2179,10 +2049,11 @@ static void rcu_prepare_for_idle(int cpu)
                if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
                        trace_rcu_prep_idle("Dyntick with callbacks");
                        rdtp->idle_gp_timer_expires =
-                                          jiffies + RCU_IDLE_GP_DELAY;
+                               round_up(jiffies + RCU_IDLE_GP_DELAY,
+                                        RCU_IDLE_GP_DELAY);
                } else {
                        rdtp->idle_gp_timer_expires =
-                                          jiffies + RCU_IDLE_LAZY_GP_DELAY;
+                               round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
                        trace_rcu_prep_idle("Dyntick with lazy callbacks");
                }
                tp = &rdtp->idle_gp_timer;
@@ -2223,8 +2094,9 @@ static void rcu_prepare_for_idle(int cpu)
        if (rcu_cpu_has_callbacks(cpu)) {
                trace_rcu_prep_idle("More callbacks");
                invoke_rcu_core();
-       } else
+       } else {
                trace_rcu_prep_idle("Callbacks drained");
+       }
 }
 
 /*
@@ -2261,6 +2133,7 @@ static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
 
 static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
 {
+       *cp = '\0';
 }
 
 #endif /* #else #ifdef CONFIG_RCU_FAST_NO_HZ */
index d4bc16ddd1d4aa09efb52cbee140f1f0b45afc36..abffb486e94ed7ea581b54861f253ca8567bddda 100644 (file)
 #define RCU_TREE_NONCORE
 #include "rcutree.h"
 
+static int show_rcubarrier(struct seq_file *m, void *unused)
+{
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp)
+               seq_printf(m, "%s: %c bcc: %d nbd: %lu\n",
+                          rsp->name, rsp->rcu_barrier_in_progress ? 'B' : '.',
+                          atomic_read(&rsp->barrier_cpu_count),
+                          rsp->n_barrier_done);
+       return 0;
+}
+
+static int rcubarrier_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcubarrier, NULL);
+}
+
+static const struct file_operations rcubarrier_fops = {
+       .owner = THIS_MODULE,
+       .open = rcubarrier_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 #ifdef CONFIG_RCU_BOOST
 
 static char convert_kthread_status(unsigned int kthread_status)
@@ -95,24 +120,16 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
                   rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
 
-#define PRINT_RCU_DATA(name, func, m) \
-       do { \
-               int _p_r_d_i; \
-               \
-               for_each_possible_cpu(_p_r_d_i) \
-                       func(m, &per_cpu(name, _p_r_d_i)); \
-       } while (0)
-
 static int show_rcudata(struct seq_file *m, void *unused)
 {
-#ifdef CONFIG_TREE_PREEMPT_RCU
-       seq_puts(m, "rcu_preempt:\n");
-       PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data, m);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-       seq_puts(m, "rcu_sched:\n");
-       PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data, m);
-       seq_puts(m, "rcu_bh:\n");
-       PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data, m);
+       int cpu;
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp) {
+               seq_printf(m, "%s:\n", rsp->name);
+               for_each_possible_cpu(cpu)
+                       print_one_rcu_data(m, per_cpu_ptr(rsp->rda, cpu));
+       }
        return 0;
 }
 
@@ -166,6 +183,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
 
 static int show_rcudata_csv(struct seq_file *m, void *unused)
 {
+       int cpu;
+       struct rcu_state *rsp;
+
        seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pgp\",\"pq\",");
        seq_puts(m, "\"dt\",\"dt nesting\",\"dt NMI nesting\",\"df\",");
        seq_puts(m, "\"of\",\"qll\",\"ql\",\"qs\"");
@@ -173,14 +193,11 @@ static int show_rcudata_csv(struct seq_file *m, void *unused)
        seq_puts(m, "\"kt\",\"ktl\"");
 #endif /* #ifdef CONFIG_RCU_BOOST */
        seq_puts(m, ",\"b\",\"ci\",\"co\",\"ca\"\n");
-#ifdef CONFIG_TREE_PREEMPT_RCU
-       seq_puts(m, "\"rcu_preempt:\"\n");
-       PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-       seq_puts(m, "\"rcu_sched:\"\n");
-       PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data_csv, m);
-       seq_puts(m, "\"rcu_bh:\"\n");
-       PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data_csv, m);
+       for_each_rcu_flavor(rsp) {
+               seq_printf(m, "\"%s:\"\n", rsp->name);
+               for_each_possible_cpu(cpu)
+                       print_one_rcu_data_csv(m, per_cpu_ptr(rsp->rda, cpu));
+       }
        return 0;
 }
 
@@ -201,8 +218,7 @@ static const struct file_operations rcudata_csv_fops = {
 
 static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp)
 {
-       seq_printf(m,  "%d:%d tasks=%c%c%c%c kt=%c ntb=%lu neb=%lu nnb=%lu "
-                  "j=%04x bt=%04x\n",
+       seq_printf(m, "%d:%d tasks=%c%c%c%c kt=%c ntb=%lu neb=%lu nnb=%lu ",
                   rnp->grplo, rnp->grphi,
                   "T."[list_empty(&rnp->blkd_tasks)],
                   "N."[!rnp->gp_tasks],
@@ -210,11 +226,11 @@ static void print_one_rcu_node_boost(struct seq_file *m, struct rcu_node *rnp)
                   "B."[!rnp->boost_tasks],
                   convert_kthread_status(rnp->boost_kthread_status),
                   rnp->n_tasks_boosted, rnp->n_exp_boosts,
-                  rnp->n_normal_boosts,
+                  rnp->n_normal_boosts);
+       seq_printf(m, "j=%04x bt=%04x\n",
                   (int)(jiffies & 0xffff),
                   (int)(rnp->boost_time & 0xffff));
-       seq_printf(m, "%s: nt=%lu egt=%lu bt=%lu nb=%lu ny=%lu nos=%lu\n",
-                  "     balk",
+       seq_printf(m, "    balk: nt=%lu egt=%lu bt=%lu nb=%lu ny=%lu nos=%lu\n",
                   rnp->n_balk_blkd_tasks,
                   rnp->n_balk_exp_gp_tasks,
                   rnp->n_balk_boost_tasks,
@@ -270,15 +286,15 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
        struct rcu_node *rnp;
 
        gpnum = rsp->gpnum;
-       seq_printf(m, "c=%lu g=%lu s=%d jfq=%ld j=%x "
-                     "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld/%ld\n",
-                  rsp->completed, gpnum, rsp->fqs_state,
+       seq_printf(m, "%s: c=%lu g=%lu s=%d jfq=%ld j=%x ",
+                  rsp->name, rsp->completed, gpnum, rsp->fqs_state,
                   (long)(rsp->jiffies_force_qs - jiffies),
-                  (int)(jiffies & 0xffff),
+                  (int)(jiffies & 0xffff));
+       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);
-       for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < NUM_RCU_NODES; rnp++) {
+       for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < rcu_num_nodes; rnp++) {
                if (rnp->level != level) {
                        seq_puts(m, "\n");
                        level = rnp->level;
@@ -295,14 +311,10 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
 
 static int show_rcuhier(struct seq_file *m, void *unused)
 {
-#ifdef CONFIG_TREE_PREEMPT_RCU
-       seq_puts(m, "rcu_preempt:\n");
-       print_one_rcu_state(m, &rcu_preempt_state);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-       seq_puts(m, "rcu_sched:\n");
-       print_one_rcu_state(m, &rcu_sched_state);
-       seq_puts(m, "rcu_bh:\n");
-       print_one_rcu_state(m, &rcu_bh_state);
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp)
+               print_one_rcu_state(m, rsp);
        return 0;
 }
 
@@ -343,11 +355,10 @@ static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)
 
 static int show_rcugp(struct seq_file *m, void *unused)
 {
-#ifdef CONFIG_TREE_PREEMPT_RCU
-       show_one_rcugp(m, &rcu_preempt_state);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-       show_one_rcugp(m, &rcu_sched_state);
-       show_one_rcugp(m, &rcu_bh_state);
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp)
+               show_one_rcugp(m, rsp);
        return 0;
 }
 
@@ -366,44 +377,36 @@ static const struct file_operations rcugp_fops = {
 
 static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp)
 {
-       seq_printf(m, "%3d%cnp=%ld "
-                  "qsp=%ld rpq=%ld cbr=%ld cng=%ld "
-                  "gpc=%ld gps=%ld nf=%ld nn=%ld\n",
+       seq_printf(m, "%3d%cnp=%ld ",
                   rdp->cpu,
                   cpu_is_offline(rdp->cpu) ? '!' : ' ',
-                  rdp->n_rcu_pending,
+                  rdp->n_rcu_pending);
+       seq_printf(m, "qsp=%ld rpq=%ld cbr=%ld cng=%ld ",
                   rdp->n_rp_qs_pending,
                   rdp->n_rp_report_qs,
                   rdp->n_rp_cb_ready,
-                  rdp->n_rp_cpu_needs_gp,
+                  rdp->n_rp_cpu_needs_gp);
+       seq_printf(m, "gpc=%ld gps=%ld nf=%ld nn=%ld\n",
                   rdp->n_rp_gp_completed,
                   rdp->n_rp_gp_started,
                   rdp->n_rp_need_fqs,
                   rdp->n_rp_need_nothing);
 }
 
-static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp)
+static int show_rcu_pending(struct seq_file *m, void *unused)
 {
        int cpu;
        struct rcu_data *rdp;
-
-       for_each_possible_cpu(cpu) {
-               rdp = per_cpu_ptr(rsp->rda, cpu);
-               if (rdp->beenonline)
-                       print_one_rcu_pending(m, rdp);
+       struct rcu_state *rsp;
+
+       for_each_rcu_flavor(rsp) {
+               seq_printf(m, "%s:\n", rsp->name);
+               for_each_possible_cpu(cpu) {
+                       rdp = per_cpu_ptr(rsp->rda, cpu);
+                       if (rdp->beenonline)
+                               print_one_rcu_pending(m, rdp);
+               }
        }
-}
-
-static int show_rcu_pending(struct seq_file *m, void *unused)
-{
-#ifdef CONFIG_TREE_PREEMPT_RCU
-       seq_puts(m, "rcu_preempt:\n");
-       print_rcu_pendings(m, &rcu_preempt_state);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-       seq_puts(m, "rcu_sched:\n");
-       print_rcu_pendings(m, &rcu_sched_state);
-       seq_puts(m, "rcu_bh:\n");
-       print_rcu_pendings(m, &rcu_bh_state);
        return 0;
 }
 
@@ -453,6 +456,11 @@ static int __init rcutree_trace_init(void)
        if (!rcudir)
                goto free_out;
 
+       retval = debugfs_create_file("rcubarrier", 0444, rcudir,
+                                               NULL, &rcubarrier_fops);
+       if (!retval)
+               goto free_out;
+
        retval = debugfs_create_file("rcudata", 0444, rcudir,
                                                NULL, &rcudata_fops);
        if (!retval)
index ab56a1764d4db8c6a5136cd3b636dc330648783b..e8cd2027abbd1e2e0ed6d432974816cef2845a42 100644 (file)
@@ -1235,6 +1235,7 @@ static ssize_t subbuf_splice_actor(struct file *in,
        struct splice_pipe_desc spd = {
                .pages = pages,
                .nr_pages = 0,
+               .nr_pages_max = PIPE_DEF_BUFFERS,
                .partial = partial,
                .flags = flags,
                .ops = &relay_pipe_buf_ops,
@@ -1302,8 +1303,8 @@ static ssize_t subbuf_splice_actor(struct file *in,
                 ret += padding;
 
 out:
-       splice_shrink_spd(pipe, &spd);
-        return ret;
+       splice_shrink_spd(&spd);
+       return ret;
 }
 
 static ssize_t relay_file_splice_read(struct file *in,
index d5594a4268d4a5bb531bcf86dfc66fe359e7c956..468bdd44c1baeb914cfc93037b86691b839ccc46 100644 (file)
@@ -2081,7 +2081,6 @@ context_switch(struct rq *rq, struct task_struct *prev,
 #endif
 
        /* Here we just switch the register state and the stack. */
-       rcu_switch_from(prev);
        switch_to(prev, next, prev);
 
        barrier();
@@ -2161,11 +2160,73 @@ unsigned long this_cpu_load(void)
 }
 
 
+/*
+ * Global load-average calculations
+ *
+ * We take a distributed and async approach to calculating the global load-avg
+ * in order to minimize overhead.
+ *
+ * The global load average is an exponentially decaying average of nr_running +
+ * nr_uninterruptible.
+ *
+ * Once every LOAD_FREQ:
+ *
+ *   nr_active = 0;
+ *   for_each_possible_cpu(cpu)
+ *     nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible;
+ *
+ *   avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n)
+ *
+ * Due to a number of reasons the above turns in the mess below:
+ *
+ *  - for_each_possible_cpu() is prohibitively expensive on machines with
+ *    serious number of cpus, therefore we need to take a distributed approach
+ *    to calculating nr_active.
+ *
+ *        \Sum_i x_i(t) = \Sum_i x_i(t) - x_i(t_0) | x_i(t_0) := 0
+ *                      = \Sum_i { \Sum_j=1 x_i(t_j) - x_i(t_j-1) }
+ *
+ *    So assuming nr_active := 0 when we start out -- true per definition, we
+ *    can simply take per-cpu deltas and fold those into a global accumulate
+ *    to obtain the same result. See calc_load_fold_active().
+ *
+ *    Furthermore, in order to avoid synchronizing all per-cpu delta folding
+ *    across the machine, we assume 10 ticks is sufficient time for every
+ *    cpu to have completed this task.
+ *
+ *    This places an upper-bound on the IRQ-off latency of the machine. Then
+ *    again, being late doesn't loose the delta, just wrecks the sample.
+ *
+ *  - cpu_rq()->nr_uninterruptible isn't accurately tracked per-cpu because
+ *    this would add another cross-cpu cacheline miss and atomic operation
+ *    to the wakeup path. Instead we increment on whatever cpu the task ran
+ *    when it went into uninterruptible state and decrement on whatever cpu
+ *    did the wakeup. This means that only the sum of nr_uninterruptible over
+ *    all cpus yields the correct result.
+ *
+ *  This covers the NO_HZ=n code, for extra head-aches, see the comment below.
+ */
+
 /* Variables and functions for calc_load */
 static atomic_long_t calc_load_tasks;
 static unsigned long calc_load_update;
 unsigned long avenrun[3];
-EXPORT_SYMBOL(avenrun);
+EXPORT_SYMBOL(avenrun); /* should be removed */
+
+/**
+ * get_avenrun - get the load average array
+ * @loads:     pointer to dest load array
+ * @offset:    offset to add
+ * @shift:     shift count to shift the result left
+ *
+ * These values are estimates at best, so no need for locking.
+ */
+void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
+{
+       loads[0] = (avenrun[0] + offset) << shift;
+       loads[1] = (avenrun[1] + offset) << shift;
+       loads[2] = (avenrun[2] + offset) << shift;
+}
 
 static long calc_load_fold_active(struct rq *this_rq)
 {
@@ -2182,6 +2243,9 @@ static long calc_load_fold_active(struct rq *this_rq)
        return delta;
 }
 
+/*
+ * a1 = a0 * e + a * (1 - e)
+ */
 static unsigned long
 calc_load(unsigned long load, unsigned long exp, unsigned long active)
 {
@@ -2193,30 +2257,118 @@ calc_load(unsigned long load, unsigned long exp, unsigned long active)
 
 #ifdef CONFIG_NO_HZ
 /*
- * For NO_HZ we delay the active fold to the next LOAD_FREQ update.
+ * Handle NO_HZ for the global load-average.
+ *
+ * Since the above described distributed algorithm to compute the global
+ * load-average relies on per-cpu sampling from the tick, it is affected by
+ * NO_HZ.
+ *
+ * The basic idea is to fold the nr_active delta into a global idle-delta upon
+ * entering NO_HZ state such that we can include this as an 'extra' cpu delta
+ * when we read the global state.
+ *
+ * Obviously reality has to ruin such a delightfully simple scheme:
+ *
+ *  - When we go NO_HZ idle during the window, we can negate our sample
+ *    contribution, causing under-accounting.
+ *
+ *    We avoid this by keeping two idle-delta counters and flipping them
+ *    when the window starts, thus separating old and new NO_HZ load.
+ *
+ *    The only trick is the slight shift in index flip for read vs write.
+ *
+ *        0s            5s            10s           15s
+ *          +10           +10           +10           +10
+ *        |-|-----------|-|-----------|-|-----------|-|
+ *    r:0 0 1           1 0           0 1           1 0
+ *    w:0 1 1           0 0           1 1           0 0
+ *
+ *    This ensures we'll fold the old idle contribution in this window while
+ *    accumlating the new one.
+ *
+ *  - When we wake up from NO_HZ idle during the window, we push up our
+ *    contribution, since we effectively move our sample point to a known
+ *    busy state.
+ *
+ *    This is solved by pushing the window forward, and thus skipping the
+ *    sample, for this cpu (effectively using the idle-delta for this cpu which
+ *    was in effect at the time the window opened). This also solves the issue
+ *    of having to deal with a cpu having been in NOHZ idle for multiple
+ *    LOAD_FREQ intervals.
  *
  * When making the ILB scale, we should try to pull this in as well.
  */
-static atomic_long_t calc_load_tasks_idle;
+static atomic_long_t calc_load_idle[2];
+static int calc_load_idx;
 
-void calc_load_account_idle(struct rq *this_rq)
+static inline int calc_load_write_idx(void)
 {
+       int idx = calc_load_idx;
+
+       /*
+        * See calc_global_nohz(), if we observe the new index, we also
+        * need to observe the new update time.
+        */
+       smp_rmb();
+
+       /*
+        * If the folding window started, make sure we start writing in the
+        * next idle-delta.
+        */
+       if (!time_before(jiffies, calc_load_update))
+               idx++;
+
+       return idx & 1;
+}
+
+static inline int calc_load_read_idx(void)
+{
+       return calc_load_idx & 1;
+}
+
+void calc_load_enter_idle(void)
+{
+       struct rq *this_rq = this_rq();
        long delta;
 
+       /*
+        * We're going into NOHZ mode, if there's any pending delta, fold it
+        * into the pending idle delta.
+        */
        delta = calc_load_fold_active(this_rq);
-       if (delta)
-               atomic_long_add(delta, &calc_load_tasks_idle);
+       if (delta) {
+               int idx = calc_load_write_idx();
+               atomic_long_add(delta, &calc_load_idle[idx]);
+       }
 }
 
-static long calc_load_fold_idle(void)
+void calc_load_exit_idle(void)
 {
-       long delta = 0;
+       struct rq *this_rq = this_rq();
+
+       /*
+        * If we're still before the sample window, we're done.
+        */
+       if (time_before(jiffies, this_rq->calc_load_update))
+               return;
 
        /*
-        * Its got a race, we don't care...
+        * We woke inside or after the sample window, this means we're already
+        * accounted through the nohz accounting, so skip the entire deal and
+        * sync up for the next window.
         */
-       if (atomic_long_read(&calc_load_tasks_idle))
-               delta = atomic_long_xchg(&calc_load_tasks_idle, 0);
+       this_rq->calc_load_update = calc_load_update;
+       if (time_before(jiffies, this_rq->calc_load_update + 10))
+               this_rq->calc_load_update += LOAD_FREQ;
+}
+
+static long calc_load_fold_idle(void)
+{
+       int idx = calc_load_read_idx();
+       long delta = 0;
+
+       if (atomic_long_read(&calc_load_idle[idx]))
+               delta = atomic_long_xchg(&calc_load_idle[idx], 0);
 
        return delta;
 }
@@ -2302,66 +2454,39 @@ static void calc_global_nohz(void)
 {
        long delta, active, n;
 
-       /*
-        * If we crossed a calc_load_update boundary, make sure to fold
-        * any pending idle changes, the respective CPUs might have
-        * missed the tick driven calc_load_account_active() update
-        * due to NO_HZ.
-        */
-       delta = calc_load_fold_idle();
-       if (delta)
-               atomic_long_add(delta, &calc_load_tasks);
-
-       /*
-        * It could be the one fold was all it took, we done!
-        */
-       if (time_before(jiffies, calc_load_update + 10))
-               return;
-
-       /*
-        * Catch-up, fold however many we are behind still
-        */
-       delta = jiffies - calc_load_update - 10;
-       n = 1 + (delta / LOAD_FREQ);
+       if (!time_before(jiffies, calc_load_update + 10)) {
+               /*
+                * Catch-up, fold however many we are behind still
+                */
+               delta = jiffies - calc_load_update - 10;
+               n = 1 + (delta / LOAD_FREQ);
 
-       active = atomic_long_read(&calc_load_tasks);
-       active = active > 0 ? active * FIXED_1 : 0;
+               active = atomic_long_read(&calc_load_tasks);
+               active = active > 0 ? active * FIXED_1 : 0;
 
-       avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
-       avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
-       avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
+               avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
+               avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
+               avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
 
-       calc_load_update += n * LOAD_FREQ;
-}
-#else
-void calc_load_account_idle(struct rq *this_rq)
-{
-}
+               calc_load_update += n * LOAD_FREQ;
+       }
 
-static inline long calc_load_fold_idle(void)
-{
-       return 0;
+       /*
+        * Flip the idle index...
+        *
+        * Make sure we first write the new time then flip the index, so that
+        * calc_load_write_idx() will see the new time when it reads the new
+        * index, this avoids a double flip messing things up.
+        */
+       smp_wmb();
+       calc_load_idx++;
 }
+#else /* !CONFIG_NO_HZ */
 
-static void calc_global_nohz(void)
-{
-}
-#endif
+static inline long calc_load_fold_idle(void) { return 0; }
+static inline void calc_global_nohz(void) { }
 
-/**
- * get_avenrun - get the load average array
- * @loads:     pointer to dest load array
- * @offset:    offset to add
- * @shift:     shift count to shift the result left
- *
- * These values are estimates at best, so no need for locking.
- */
-void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
-{
-       loads[0] = (avenrun[0] + offset) << shift;
-       loads[1] = (avenrun[1] + offset) << shift;
-       loads[2] = (avenrun[2] + offset) << shift;
-}
+#endif /* CONFIG_NO_HZ */
 
 /*
  * calc_load - update the avenrun load estimates 10 ticks after the
@@ -2369,11 +2494,18 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
  */
 void calc_global_load(unsigned long ticks)
 {
-       long active;
+       long active, delta;
 
        if (time_before(jiffies, calc_load_update + 10))
                return;
 
+       /*
+        * Fold the 'old' idle-delta to include all NO_HZ cpus.
+        */
+       delta = calc_load_fold_idle();
+       if (delta)
+               atomic_long_add(delta, &calc_load_tasks);
+
        active = atomic_long_read(&calc_load_tasks);
        active = active > 0 ? active * FIXED_1 : 0;
 
@@ -2384,12 +2516,7 @@ void calc_global_load(unsigned long ticks)
        calc_load_update += LOAD_FREQ;
 
        /*
-        * Account one period with whatever state we found before
-        * folding in the nohz state and ageing the entire idle period.
-        *
-        * This avoids loosing a sample when we go idle between 
-        * calc_load_account_active() (10 ticks ago) and now and thus
-        * under-accounting.
+        * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk.
         */
        calc_global_nohz();
 }
@@ -2406,13 +2533,16 @@ static void calc_load_account_active(struct rq *this_rq)
                return;
 
        delta  = calc_load_fold_active(this_rq);
-       delta += calc_load_fold_idle();
        if (delta)
                atomic_long_add(delta, &calc_load_tasks);
 
        this_rq->calc_load_update += LOAD_FREQ;
 }
 
+/*
+ * End of global load-average stuff
+ */
+
 /*
  * The exact cpuload at various idx values, calculated at every tick would be
  * load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load
index b44d604b35d1a8b4164aa2ea4d94d00bf9063824..b6baf370cae973707c24389b30b38e43c76bb4d7 100644 (file)
@@ -25,7 +25,6 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl
 static struct task_struct *pick_next_task_idle(struct rq *rq)
 {
        schedstat_inc(rq, sched_goidle);
-       calc_load_account_idle(rq);
        return rq->idle;
 }
 
index 6d52cea7f33dc77496ec6db9e975cd2c0fd1c2b9..55844f24435a0ad5c1c50561a54424ce4b25992d 100644 (file)
@@ -942,8 +942,6 @@ static inline u64 sched_avg_period(void)
        return (u64)sysctl_sched_time_avg * NSEC_PER_MSEC / 2;
 }
 
-void calc_load_account_idle(struct rq *this_rq);
-
 #ifdef CONFIG_SCHED_HRTICK
 
 /*
index 677102789cf22d4847936782f6c6f67085421927..be4f856d52f81bab8184544b5dd6dd9b823bc21b 100644 (file)
@@ -1971,6 +1971,13 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
 void ptrace_notify(int exit_code)
 {
        BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);
+       if (unlikely(current->task_works)) {
+               if (test_and_clear_ti_thread_flag(current_thread_info(),
+                                                  TIF_NOTIFY_RESUME)) {
+                       smp_mb__after_clear_bit();
+                       task_work_run();
+               }
+       }
 
        spin_lock_irq(&current->sighand->siglock);
        ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED);
@@ -2191,6 +2198,14 @@ int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
        struct signal_struct *signal = current->signal;
        int signr;
 
+       if (unlikely(current->task_works)) {
+               if (test_and_clear_ti_thread_flag(current_thread_info(),
+                                                  TIF_NOTIFY_RESUME)) {
+                       smp_mb__after_clear_bit();
+                       task_work_run();
+               }
+       }
+
        if (unlikely(uprobe_deny_signal()))
                return 0;
 
index d0ae5b24875e0f73659d79ae6cd3f9ee11d5ab41..29dd40a9f2f403ab86f39c96ddb505851b1d36c2 100644 (file)
@@ -581,26 +581,6 @@ int smp_call_function(smp_call_func_t func, void *info, int wait)
        return 0;
 }
 EXPORT_SYMBOL(smp_call_function);
-
-void ipi_call_lock(void)
-{
-       raw_spin_lock(&call_function.lock);
-}
-
-void ipi_call_unlock(void)
-{
-       raw_spin_unlock(&call_function.lock);
-}
-
-void ipi_call_lock_irq(void)
-{
-       raw_spin_lock_irq(&call_function.lock);
-}
-
-void ipi_call_unlock_irq(void)
-{
-       raw_spin_unlock_irq(&call_function.lock);
-}
 #endif /* USE_GENERIC_SMP_HELPERS */
 
 /* Setup configured maximum number of CPUs to activate */
index 80c0acfb847211af69e9356677f45f8ea1c4c240..6ef9433e1c7001ff0d00799379de7e71ef1a0113 100644 (file)
@@ -3,8 +3,6 @@
 
 struct task_struct;
 
-int smpboot_prepare(unsigned int cpu);
-
 #ifdef CONFIG_GENERIC_SMP_IDLE_THREAD
 struct task_struct *idle_thread_get(unsigned int cpu);
 void idle_thread_set_boot_cpu(void);
index e0c8ffc50d7fc48bfaa73f43946638a47c947fdb..2d39a84cd8575e6295f666421cee01b41652b3b1 100644 (file)
@@ -1788,7 +1788,6 @@ SYSCALL_DEFINE1(umask, int, mask)
 #ifdef CONFIG_CHECKPOINT_RESTORE
 static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
 {
-       struct vm_area_struct *vma;
        struct file *exe_file;
        struct dentry *dentry;
        int err;
@@ -1816,13 +1815,17 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
        down_write(&mm->mmap_sem);
 
        /*
-        * Forbid mm->exe_file change if there are mapped other files.
+        * Forbid mm->exe_file change if old file still mapped.
         */
        err = -EBUSY;
-       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-               if (vma->vm_file && !path_equal(&vma->vm_file->f_path,
-                                               &exe_file->f_path))
-                       goto exit_unlock;
+       if (mm->exe_file) {
+               struct vm_area_struct *vma;
+
+               for (vma = mm->mmap; vma; vma = vma->vm_next)
+                       if (vma->vm_file &&
+                           path_equal(&vma->vm_file->f_path,
+                                      &mm->exe_file->f_path))
+                               goto exit_unlock;
        }
 
        /*
@@ -1835,6 +1838,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
        if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags))
                goto exit_unlock;
 
+       err = 0;
        set_mm_exe_file(mm, exe_file);
 exit_unlock:
        up_write(&mm->mmap_sem);
index 82d1c794066d450d6c08c6de4452a9cbd344ef63..91d4e1742a0c4ec1cd8805b6663f5a95b5d42b3b 100644 (file)
@@ -3,82 +3,78 @@
 #include <linux/tracehook.h>
 
 int
-task_work_add(struct task_struct *task, struct task_work *twork, bool notify)
+task_work_add(struct task_struct *task, struct callback_head *twork, bool notify)
 {
+       struct callback_head *last, *first;
        unsigned long flags;
-       int err = -ESRCH;
 
-#ifndef TIF_NOTIFY_RESUME
-       if (notify)
-               return -ENOTSUPP;
-#endif
        /*
-        * We must not insert the new work if the task has already passed
-        * exit_task_work(). We rely on do_exit()->raw_spin_unlock_wait()
-        * and check PF_EXITING under pi_lock.
+        * Not inserting the new work if the task has already passed
+        * exit_task_work() is the responisbility of callers.
         */
        raw_spin_lock_irqsave(&task->pi_lock, flags);
-       if (likely(!(task->flags & PF_EXITING))) {
-               hlist_add_head(&twork->hlist, &task->task_works);
-               err = 0;
-       }
+       last = task->task_works;
+       first = last ? last->next : twork;
+       twork->next = first;
+       if (last)
+               last->next = twork;
+       task->task_works = twork;
        raw_spin_unlock_irqrestore(&task->pi_lock, flags);
 
        /* test_and_set_bit() implies mb(), see tracehook_notify_resume(). */
-       if (likely(!err) && notify)
+       if (notify)
                set_notify_resume(task);
-       return err;
+       return 0;
 }
 
-struct task_work *
+struct callback_head *
 task_work_cancel(struct task_struct *task, task_work_func_t func)
 {
        unsigned long flags;
-       struct task_work *twork;
-       struct hlist_node *pos;
+       struct callback_head *last, *res = NULL;
 
        raw_spin_lock_irqsave(&task->pi_lock, flags);
-       hlist_for_each_entry(twork, pos, &task->task_works, hlist) {
-               if (twork->func == func) {
-                       hlist_del(&twork->hlist);
-                       goto found;
+       last = task->task_works;
+       if (last) {
+               struct callback_head *q = last, *p = q->next;
+               while (1) {
+                       if (p->func == func) {
+                               q->next = p->next;
+                               if (p == last)
+                                       task->task_works = q == p ? NULL : q;
+                               res = p;
+                               break;
+                       }
+                       if (p == last)
+                               break;
+                       q = p;
+                       p = q->next;
                }
        }
-       twork = NULL;
- found:
        raw_spin_unlock_irqrestore(&task->pi_lock, flags);
-
-       return twork;
+       return res;
 }
 
 void task_work_run(void)
 {
        struct task_struct *task = current;
-       struct hlist_head task_works;
-       struct hlist_node *pos;
+       struct callback_head *p, *q;
 
-       raw_spin_lock_irq(&task->pi_lock);
-       hlist_move_list(&task->task_works, &task_works);
-       raw_spin_unlock_irq(&task->pi_lock);
+       while (1) {
+               raw_spin_lock_irq(&task->pi_lock);
+               p = task->task_works;
+               task->task_works = NULL;
+               raw_spin_unlock_irq(&task->pi_lock);
 
-       if (unlikely(hlist_empty(&task_works)))
-               return;
-       /*
-        * We use hlist to save the space in task_struct, but we want fifo.
-        * Find the last entry, the list should be short, then process them
-        * in reverse order.
-        */
-       for (pos = task_works.first; pos->next; pos = pos->next)
-               ;
+               if (unlikely(!p))
+                       return;
 
-       for (;;) {
-               struct hlist_node **pprev = pos->pprev;
-               struct task_work *twork = container_of(pos, struct task_work,
-                                                       hlist);
-               twork->func(twork);
-
-               if (pprev == &task_works.first)
-                       break;
-               pos = container_of(pprev, struct hlist_node, next);
+               q = p->next; /* head */
+               p->next = NULL; /* cut it */
+               while (q) {
+                       p = q->next;
+                       q->func(q);
+                       q = p;
+               }
        }
 }
index 70b33abcc7bb0e92762b05af6c6ceaa1be75cd38..b7fbadc5c973c928e531cf6d701f1520e4809812 100644 (file)
@@ -409,7 +409,9 @@ int second_overflow(unsigned long secs)
                        time_state = TIME_DEL;
                break;
        case TIME_INS:
-               if (secs % 86400 == 0) {
+               if (!(time_status & STA_INS))
+                       time_state = TIME_OK;
+               else if (secs % 86400 == 0) {
                        leap = -1;
                        time_state = TIME_OOP;
                        time_tai++;
@@ -418,7 +420,9 @@ int second_overflow(unsigned long secs)
                }
                break;
        case TIME_DEL:
-               if ((secs + 1) % 86400 == 0) {
+               if (!(time_status & STA_DEL))
+                       time_state = TIME_OK;
+               else if ((secs + 1) % 86400 == 0) {
                        leap = 1;
                        time_tai--;
                        time_state = TIME_WAIT;
index 8699978339286b444d2d096dd3f0e9b6fba5c898..024540f97f74c3e94205826f33d3968ea765f626 100644 (file)
@@ -105,7 +105,7 @@ static ktime_t tick_init_jiffy_update(void)
 /*
  * NO HZ enabled ?
  */
-static int tick_nohz_enabled __read_mostly  = 1;
+int tick_nohz_enabled __read_mostly  = 1;
 
 /*
  * Enable / Disable tickless mode
@@ -271,50 +271,15 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
 }
 EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
 
-static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
+static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
+                                        ktime_t now, int cpu)
 {
        unsigned long seq, last_jiffies, next_jiffies, delta_jiffies;
+       ktime_t last_update, expires, ret = { .tv64 = 0 };
        unsigned long rcu_delta_jiffies;
-       ktime_t last_update, expires, now;
        struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
        u64 time_delta;
-       int cpu;
-
-       cpu = smp_processor_id();
-       ts = &per_cpu(tick_cpu_sched, cpu);
-
-       now = tick_nohz_start_idle(cpu, ts);
-
-       /*
-        * If this cpu is offline and it is the one which updates
-        * jiffies, then give up the assignment and let it be taken by
-        * the cpu which runs the tick timer next. If we don't drop
-        * this here the jiffies might be stale and do_timer() never
-        * invoked.
-        */
-       if (unlikely(!cpu_online(cpu))) {
-               if (cpu == tick_do_timer_cpu)
-                       tick_do_timer_cpu = TICK_DO_TIMER_NONE;
-       }
-
-       if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
-               return;
 
-       if (need_resched())
-               return;
-
-       if (unlikely(local_softirq_pending() && cpu_online(cpu))) {
-               static int ratelimit;
-
-               if (ratelimit < 10) {
-                       printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
-                              (unsigned int) local_softirq_pending());
-                       ratelimit++;
-               }
-               return;
-       }
-
-       ts->idle_calls++;
        /* Read jiffies and the time when jiffies were updated last */
        do {
                seq = read_seqbegin(&xtime_lock);
@@ -397,6 +362,8 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
                if (ts->tick_stopped && ktime_equal(expires, dev->next_event))
                        goto out;
 
+               ret = expires;
+
                /*
                 * nohz_stop_sched_tick can be called several times before
                 * the nohz_restart_sched_tick is called. This happens when
@@ -406,17 +373,12 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts)
                 */
                if (!ts->tick_stopped) {
                        select_nohz_load_balancer(1);
+                       calc_load_enter_idle();
 
-                       ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
+                       ts->last_tick = hrtimer_get_expires(&ts->sched_timer);
                        ts->tick_stopped = 1;
-                       ts->idle_jiffies = last_jiffies;
                }
 
-               ts->idle_sleeps++;
-
-               /* Mark expires */
-               ts->idle_expires = expires;
-
                /*
                 * If the expiration time == KTIME_MAX, then
                 * in this case we simply stop the tick timer.
@@ -447,6 +409,65 @@ out:
        ts->next_jiffies = next_jiffies;
        ts->last_jiffies = last_jiffies;
        ts->sleep_length = ktime_sub(dev->next_event, now);
+
+       return ret;
+}
+
+static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
+{
+       /*
+        * If this cpu is offline and it is the one which updates
+        * jiffies, then give up the assignment and let it be taken by
+        * the cpu which runs the tick timer next. If we don't drop
+        * this here the jiffies might be stale and do_timer() never
+        * invoked.
+        */
+       if (unlikely(!cpu_online(cpu))) {
+               if (cpu == tick_do_timer_cpu)
+                       tick_do_timer_cpu = TICK_DO_TIMER_NONE;
+       }
+
+       if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
+               return false;
+
+       if (need_resched())
+               return false;
+
+       if (unlikely(local_softirq_pending() && cpu_online(cpu))) {
+               static int ratelimit;
+
+               if (ratelimit < 10) {
+                       printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
+                              (unsigned int) local_softirq_pending());
+                       ratelimit++;
+               }
+               return false;
+       }
+
+       return true;
+}
+
+static void __tick_nohz_idle_enter(struct tick_sched *ts)
+{
+       ktime_t now, expires;
+       int cpu = smp_processor_id();
+
+       now = tick_nohz_start_idle(cpu, ts);
+
+       if (can_stop_idle_tick(cpu, ts)) {
+               int was_stopped = ts->tick_stopped;
+
+               ts->idle_calls++;
+
+               expires = tick_nohz_stop_sched_tick(ts, now, cpu);
+               if (expires.tv64 > 0LL) {
+                       ts->idle_sleeps++;
+                       ts->idle_expires = expires;
+               }
+
+               if (!was_stopped && ts->tick_stopped)
+                       ts->idle_jiffies = ts->last_jiffies;
+       }
 }
 
 /**
@@ -484,7 +505,7 @@ void tick_nohz_idle_enter(void)
         * update of the idle time accounting in tick_nohz_start_idle().
         */
        ts->inidle = 1;
-       tick_nohz_stop_sched_tick(ts);
+       __tick_nohz_idle_enter(ts);
 
        local_irq_enable();
 }
@@ -504,7 +525,7 @@ void tick_nohz_irq_exit(void)
        if (!ts->inidle)
                return;
 
-       tick_nohz_stop_sched_tick(ts);
+       __tick_nohz_idle_enter(ts);
 }
 
 /**
@@ -522,7 +543,7 @@ ktime_t tick_nohz_get_sleep_length(void)
 static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
 {
        hrtimer_cancel(&ts->sched_timer);
-       hrtimer_set_expires(&ts->sched_timer, ts->idle_tick);
+       hrtimer_set_expires(&ts->sched_timer, ts->last_tick);
 
        while (1) {
                /* Forward the time to expire in the future */
@@ -545,6 +566,41 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
        }
 }
 
+static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
+{
+       /* Update jiffies first */
+       select_nohz_load_balancer(0);
+       tick_do_update_jiffies64(now);
+       update_cpu_load_nohz();
+
+       touch_softlockup_watchdog();
+       /*
+        * Cancel the scheduled timer and restore the tick
+        */
+       ts->tick_stopped  = 0;
+       ts->idle_exittime = now;
+
+       tick_nohz_restart(ts, now);
+}
+
+static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
+{
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+       unsigned long ticks;
+       /*
+        * We stopped the tick in idle. Update process times would miss the
+        * time we slept as update_process_times does only a 1 tick
+        * accounting. Enforce that this is accounted to idle !
+        */
+       ticks = jiffies - ts->idle_jiffies;
+       /*
+        * We might be one off. Do not randomly account a huge number of ticks!
+        */
+       if (ticks && ticks < LONG_MAX)
+               account_idle_ticks(ticks);
+#endif
+}
+
 /**
  * tick_nohz_idle_exit - restart the idle tick from the idle task
  *
@@ -556,9 +612,6 @@ void tick_nohz_idle_exit(void)
 {
        int cpu = smp_processor_id();
        struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-       unsigned long ticks;
-#endif
        ktime_t now;
 
        local_irq_disable();
@@ -573,39 +626,11 @@ void tick_nohz_idle_exit(void)
        if (ts->idle_active)
                tick_nohz_stop_idle(cpu, now);
 
-       if (!ts->tick_stopped) {
-               local_irq_enable();
-               return;
+       if (ts->tick_stopped) {
+               tick_nohz_restart_sched_tick(ts, now);
+               tick_nohz_account_idle_ticks(ts);
        }
 
-       /* Update jiffies first */
-       select_nohz_load_balancer(0);
-       tick_do_update_jiffies64(now);
-       update_cpu_load_nohz();
-
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-       /*
-        * We stopped the tick in idle. Update process times would miss the
-        * time we slept as update_process_times does only a 1 tick
-        * accounting. Enforce that this is accounted to idle !
-        */
-       ticks = jiffies - ts->idle_jiffies;
-       /*
-        * We might be one off. Do not randomly account a huge number of ticks!
-        */
-       if (ticks && ticks < LONG_MAX)
-               account_idle_ticks(ticks);
-#endif
-
-       touch_softlockup_watchdog();
-       /*
-        * Cancel the scheduled timer and restore the tick
-        */
-       ts->tick_stopped  = 0;
-       ts->idle_exittime = now;
-
-       tick_nohz_restart(ts, now);
-
        local_irq_enable();
 }
 
@@ -809,7 +834,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
                 */
                if (ts->tick_stopped) {
                        touch_softlockup_watchdog();
-                       ts->idle_jiffies++;
+                       if (idle_cpu(cpu))
+                               ts->idle_jiffies++;
                }
                update_process_times(user_mode(regs));
                profile_tick(CPU_PROFILING);
index 6f46a00a1e8a703118ab9d8be3905758f08185c8..f045cc50832d0fc8aee045755d3ba60d655f2647 100644 (file)
 /* Structure holding internal timekeeping values. */
 struct timekeeper {
        /* Current clocksource used for timekeeping. */
-       struct clocksource *clock;
+       struct clocksource      *clock;
        /* NTP adjusted clock multiplier */
-       u32     mult;
+       u32                     mult;
        /* The shift value of the current clocksource. */
-       int     shift;
-
+       u32                     shift;
        /* Number of clock cycles in one NTP interval. */
-       cycle_t cycle_interval;
+       cycle_t                 cycle_interval;
        /* Number of clock shifted nano seconds in one NTP interval. */
-       u64     xtime_interval;
+       u64                     xtime_interval;
        /* shifted nano seconds left over when rounding cycle_interval */
-       s64     xtime_remainder;
+       s64                     xtime_remainder;
        /* Raw nano seconds accumulated per NTP interval. */
-       u32     raw_interval;
+       u32                     raw_interval;
+
+       /* Current CLOCK_REALTIME time in seconds */
+       u64                     xtime_sec;
+       /* Clock shifted nano seconds */
+       u64                     xtime_nsec;
 
-       /* Clock shifted nano seconds remainder not stored in xtime.tv_nsec. */
-       u64     xtime_nsec;
        /* Difference between accumulated time and NTP time in ntp
         * shifted nano seconds. */
-       s64     ntp_error;
+       s64                     ntp_error;
        /* Shift conversion between clock shifted nano seconds and
         * ntp shifted nano seconds. */
-       int     ntp_error_shift;
+       u32                     ntp_error_shift;
 
-       /* The current time */
-       struct timespec xtime;
        /*
         * wall_to_monotonic is what we need to add to xtime (or xtime corrected
         * for sub jiffie times) to get to monotonic time.  Monotonic is pegged
@@ -64,14 +64,17 @@ struct timekeeper {
         * - wall_to_monotonic is no longer the boot time, getboottime must be
         * used instead.
         */
-       struct timespec wall_to_monotonic;
+       struct timespec         wall_to_monotonic;
        /* time spent in suspend */
-       struct timespec total_sleep_time;
+       struct timespec         total_sleep_time;
        /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
-       struct timespec raw_time;
-
+       struct timespec         raw_time;
+       /* Offset clock monotonic -> clock realtime */
+       ktime_t                 offs_real;
+       /* Offset clock monotonic -> clock boottime */
+       ktime_t                 offs_boot;
        /* Seqlock for all timekeeper values */
-       seqlock_t lock;
+       seqlock_t               lock;
 };
 
 static struct timekeeper timekeeper;
@@ -82,11 +85,37 @@ static struct timekeeper timekeeper;
  */
 __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
 
-
 /* flag for if timekeeping is suspended */
 int __read_mostly timekeeping_suspended;
 
+static inline void tk_normalize_xtime(struct timekeeper *tk)
+{
+       while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) {
+               tk->xtime_nsec -= (u64)NSEC_PER_SEC << tk->shift;
+               tk->xtime_sec++;
+       }
+}
+
+static struct timespec tk_xtime(struct timekeeper *tk)
+{
+       struct timespec ts;
+
+       ts.tv_sec = tk->xtime_sec;
+       ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift);
+       return ts;
+}
+
+static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts)
+{
+       tk->xtime_sec = ts->tv_sec;
+       tk->xtime_nsec = ts->tv_nsec << tk->shift;
+}
 
+static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts)
+{
+       tk->xtime_sec += ts->tv_sec;
+       tk->xtime_nsec += ts->tv_nsec << tk->shift;
+}
 
 /**
  * timekeeper_setup_internals - Set up internals to use clocksource clock.
@@ -98,12 +127,14 @@ int __read_mostly timekeeping_suspended;
  *
  * Unless you're the timekeeping code, you should not be using this!
  */
-static void timekeeper_setup_internals(struct clocksource *clock)
+static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
 {
        cycle_t interval;
        u64 tmp, ntpinterval;
+       struct clocksource *old_clock;
 
-       timekeeper.clock = clock;
+       old_clock = tk->clock;
+       tk->clock = clock;
        clock->cycle_last = clock->read(clock);
 
        /* Do the ns -> cycle conversion first, using original mult */
@@ -116,71 +147,96 @@ static void timekeeper_setup_internals(struct clocksource *clock)
                tmp = 1;
 
        interval = (cycle_t) tmp;
-       timekeeper.cycle_interval = interval;
+       tk->cycle_interval = interval;
 
        /* Go back from cycles -> shifted ns */
-       timekeeper.xtime_interval = (u64) interval * clock->mult;
-       timekeeper.xtime_remainder = ntpinterval - timekeeper.xtime_interval;
-       timekeeper.raw_interval =
+       tk->xtime_interval = (u64) interval * clock->mult;
+       tk->xtime_remainder = ntpinterval - tk->xtime_interval;
+       tk->raw_interval =
                ((u64) interval * clock->mult) >> clock->shift;
 
-       timekeeper.xtime_nsec = 0;
-       timekeeper.shift = clock->shift;
+        /* if changing clocks, convert xtime_nsec shift units */
+       if (old_clock) {
+               int shift_change = clock->shift - old_clock->shift;
+               if (shift_change < 0)
+                       tk->xtime_nsec >>= -shift_change;
+               else
+                       tk->xtime_nsec <<= shift_change;
+       }
+       tk->shift = clock->shift;
 
-       timekeeper.ntp_error = 0;
-       timekeeper.ntp_error_shift = NTP_SCALE_SHIFT - clock->shift;
+       tk->ntp_error = 0;
+       tk->ntp_error_shift = NTP_SCALE_SHIFT - clock->shift;
 
        /*
         * The timekeeper keeps its own mult values for the currently
         * active clocksource. These value will be adjusted via NTP
         * to counteract clock drifting.
         */
-       timekeeper.mult = clock->mult;
+       tk->mult = clock->mult;
 }
 
 /* Timekeeper helper functions. */
-static inline s64 timekeeping_get_ns(void)
+static inline s64 timekeeping_get_ns(struct timekeeper *tk)
 {
        cycle_t cycle_now, cycle_delta;
        struct clocksource *clock;
+       s64 nsec;
 
        /* read clocksource: */
-       clock = timekeeper.clock;
+       clock = tk->clock;
        cycle_now = clock->read(clock);
 
        /* calculate the delta since the last update_wall_time: */
        cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
 
-       /* return delta convert to nanoseconds using ntp adjusted mult. */
-       return clocksource_cyc2ns(cycle_delta, timekeeper.mult,
-                                 timekeeper.shift);
+       nsec = cycle_delta * tk->mult + tk->xtime_nsec;
+       nsec >>= tk->shift;
+
+       /* If arch requires, add in gettimeoffset() */
+       return nsec + arch_gettimeoffset();
 }
 
-static inline s64 timekeeping_get_ns_raw(void)
+static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
 {
        cycle_t cycle_now, cycle_delta;
        struct clocksource *clock;
+       s64 nsec;
 
        /* read clocksource: */
-       clock = timekeeper.clock;
+       clock = tk->clock;
        cycle_now = clock->read(clock);
 
        /* calculate the delta since the last update_wall_time: */
        cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
 
-       /* return delta convert to nanoseconds. */
-       return clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
+       /* convert delta to nanoseconds. */
+       nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
+
+       /* If arch requires, add in gettimeoffset() */
+       return nsec + arch_gettimeoffset();
+}
+
+static void update_rt_offset(struct timekeeper *tk)
+{
+       struct timespec tmp, *wtm = &tk->wall_to_monotonic;
+
+       set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec);
+       tk->offs_real = timespec_to_ktime(tmp);
 }
 
 /* must hold write on timekeeper.lock */
-static void timekeeping_update(bool clearntp)
+static void timekeeping_update(struct timekeeper *tk, bool clearntp)
 {
+       struct timespec xt;
+
        if (clearntp) {
-               timekeeper.ntp_error = 0;
+               tk->ntp_error = 0;
                ntp_clear();
        }
-       update_vsyscall(&timekeeper.xtime, &timekeeper.wall_to_monotonic,
-                        timekeeper.clock, timekeeper.mult);
+       update_rt_offset(tk);
+       xt = tk_xtime(tk);
+       update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult);
 }
 
 
@@ -191,27 +247,26 @@ static void timekeeping_update(bool clearntp)
  * update_wall_time(). This is useful before significant clock changes,
  * as it avoids having to deal with this time offset explicitly.
  */
-static void timekeeping_forward_now(void)
+static void timekeeping_forward_now(struct timekeeper *tk)
 {
        cycle_t cycle_now, cycle_delta;
        struct clocksource *clock;
        s64 nsec;
 
-       clock = timekeeper.clock;
+       clock = tk->clock;
        cycle_now = clock->read(clock);
        cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
        clock->cycle_last = cycle_now;
 
-       nsec = clocksource_cyc2ns(cycle_delta, timekeeper.mult,
-                                 timekeeper.shift);
+       tk->xtime_nsec += cycle_delta * tk->mult;
 
        /* If arch requires, add in gettimeoffset() */
-       nsec += arch_gettimeoffset();
+       tk->xtime_nsec += arch_gettimeoffset() << tk->shift;
 
-       timespec_add_ns(&timekeeper.xtime, nsec);
+       tk_normalize_xtime(tk);
 
        nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
-       timespec_add_ns(&timekeeper.raw_time, nsec);
+       timespec_add_ns(&tk->raw_time, nsec);
 }
 
 /**
@@ -223,18 +278,15 @@ static void timekeeping_forward_now(void)
 void getnstimeofday(struct timespec *ts)
 {
        unsigned long seq;
-       s64 nsecs;
+       s64 nsecs = 0;
 
        WARN_ON(timekeeping_suspended);
 
        do {
                seq = read_seqbegin(&timekeeper.lock);
 
-               *ts = timekeeper.xtime;
-               nsecs = timekeeping_get_ns();
-
-               /* If arch requires, add in gettimeoffset() */
-               nsecs += arch_gettimeoffset();
+               ts->tv_sec = timekeeper.xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
 
        } while (read_seqretry(&timekeeper.lock, seq));
 
@@ -251,13 +303,10 @@ ktime_t ktime_get(void)
 
        do {
                seq = read_seqbegin(&timekeeper.lock);
-               secs = timekeeper.xtime.tv_sec +
+               secs = timekeeper.xtime_sec +
                                timekeeper.wall_to_monotonic.tv_sec;
-               nsecs = timekeeper.xtime.tv_nsec +
+               nsecs = timekeeping_get_ns(&timekeeper) +
                                timekeeper.wall_to_monotonic.tv_nsec;
-               nsecs += timekeeping_get_ns();
-               /* If arch requires, add in gettimeoffset() */
-               nsecs += arch_gettimeoffset();
 
        } while (read_seqretry(&timekeeper.lock, seq));
        /*
@@ -280,22 +329,19 @@ void ktime_get_ts(struct timespec *ts)
 {
        struct timespec tomono;
        unsigned int seq;
-       s64 nsecs;
 
        WARN_ON(timekeeping_suspended);
 
        do {
                seq = read_seqbegin(&timekeeper.lock);
-               *ts = timekeeper.xtime;
+               ts->tv_sec = timekeeper.xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
                tomono = timekeeper.wall_to_monotonic;
-               nsecs = timekeeping_get_ns();
-               /* If arch requires, add in gettimeoffset() */
-               nsecs += arch_gettimeoffset();
 
        } while (read_seqretry(&timekeeper.lock, seq));
 
        set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
-                               ts->tv_nsec + tomono.tv_nsec + nsecs);
+                               ts->tv_nsec + tomono.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(ktime_get_ts);
 
@@ -318,20 +364,14 @@ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
        WARN_ON_ONCE(timekeeping_suspended);
 
        do {
-               u32 arch_offset;
-
                seq = read_seqbegin(&timekeeper.lock);
 
                *ts_raw = timekeeper.raw_time;
-               *ts_real = timekeeper.xtime;
-
-               nsecs_raw = timekeeping_get_ns_raw();
-               nsecs_real = timekeeping_get_ns();
+               ts_real->tv_sec = timekeeper.xtime_sec;
+               ts_real->tv_nsec = 0;
 
-               /* If arch requires, add in gettimeoffset() */
-               arch_offset = arch_gettimeoffset();
-               nsecs_raw += arch_offset;
-               nsecs_real += arch_offset;
+               nsecs_raw = timekeeping_get_ns_raw(&timekeeper);
+               nsecs_real = timekeeping_get_ns(&timekeeper);
 
        } while (read_seqretry(&timekeeper.lock, seq));
 
@@ -366,7 +406,7 @@ EXPORT_SYMBOL(do_gettimeofday);
  */
 int do_settimeofday(const struct timespec *tv)
 {
-       struct timespec ts_delta;
+       struct timespec ts_delta, xt;
        unsigned long flags;
 
        if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
@@ -374,15 +414,18 @@ int do_settimeofday(const struct timespec *tv)
 
        write_seqlock_irqsave(&timekeeper.lock, flags);
 
-       timekeeping_forward_now();
+       timekeeping_forward_now(&timekeeper);
+
+       xt = tk_xtime(&timekeeper);
+       ts_delta.tv_sec = tv->tv_sec - xt.tv_sec;
+       ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec;
 
-       ts_delta.tv_sec = tv->tv_sec - timekeeper.xtime.tv_sec;
-       ts_delta.tv_nsec = tv->tv_nsec - timekeeper.xtime.tv_nsec;
        timekeeper.wall_to_monotonic =
                        timespec_sub(timekeeper.wall_to_monotonic, ts_delta);
 
-       timekeeper.xtime = *tv;
-       timekeeping_update(true);
+       tk_set_xtime(&timekeeper, tv);
+
+       timekeeping_update(&timekeeper, true);
 
        write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
@@ -409,13 +452,14 @@ int timekeeping_inject_offset(struct timespec *ts)
 
        write_seqlock_irqsave(&timekeeper.lock, flags);
 
-       timekeeping_forward_now();
+       timekeeping_forward_now(&timekeeper);
 
-       timekeeper.xtime = timespec_add(timekeeper.xtime, *ts);
+
+       tk_xtime_add(&timekeeper, ts);
        timekeeper.wall_to_monotonic =
                                timespec_sub(timekeeper.wall_to_monotonic, *ts);
 
-       timekeeping_update(true);
+       timekeeping_update(&timekeeper, true);
 
        write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
@@ -440,14 +484,14 @@ static int change_clocksource(void *data)
 
        write_seqlock_irqsave(&timekeeper.lock, flags);
 
-       timekeeping_forward_now();
+       timekeeping_forward_now(&timekeeper);
        if (!new->enable || new->enable(new) == 0) {
                old = timekeeper.clock;
-               timekeeper_setup_internals(new);
+               tk_setup_internals(&timekeeper, new);
                if (old->disable)
                        old->disable(old);
        }
-       timekeeping_update(true);
+       timekeeping_update(&timekeeper, true);
 
        write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
@@ -497,7 +541,7 @@ void getrawmonotonic(struct timespec *ts)
 
        do {
                seq = read_seqbegin(&timekeeper.lock);
-               nsecs = timekeeping_get_ns_raw();
+               nsecs = timekeeping_get_ns_raw(&timekeeper);
                *ts = timekeeper.raw_time;
 
        } while (read_seqretry(&timekeeper.lock, seq));
@@ -532,6 +576,7 @@ u64 timekeeping_max_deferment(void)
 {
        unsigned long seq;
        u64 ret;
+
        do {
                seq = read_seqbegin(&timekeeper.lock);
 
@@ -592,18 +637,17 @@ void __init timekeeping_init(void)
        clock = clocksource_default_clock();
        if (clock->enable)
                clock->enable(clock);
-       timekeeper_setup_internals(clock);
+       tk_setup_internals(&timekeeper, clock);
 
-       timekeeper.xtime.tv_sec = now.tv_sec;
-       timekeeper.xtime.tv_nsec = now.tv_nsec;
+       tk_set_xtime(&timekeeper, &now);
        timekeeper.raw_time.tv_sec = 0;
        timekeeper.raw_time.tv_nsec = 0;
-       if (boot.tv_sec == 0 && boot.tv_nsec == 0) {
-               boot.tv_sec = timekeeper.xtime.tv_sec;
-               boot.tv_nsec = timekeeper.xtime.tv_nsec;
-       }
+       if (boot.tv_sec == 0 && boot.tv_nsec == 0)
+               boot = tk_xtime(&timekeeper);
+
        set_normalized_timespec(&timekeeper.wall_to_monotonic,
                                -boot.tv_sec, -boot.tv_nsec);
+       update_rt_offset(&timekeeper);
        timekeeper.total_sleep_time.tv_sec = 0;
        timekeeper.total_sleep_time.tv_nsec = 0;
        write_sequnlock_irqrestore(&timekeeper.lock, flags);
@@ -612,6 +656,12 @@ void __init timekeeping_init(void)
 /* time in seconds when suspend began */
 static struct timespec timekeeping_suspend_time;
 
+static void update_sleep_time(struct timespec t)
+{
+       timekeeper.total_sleep_time = t;
+       timekeeper.offs_boot = timespec_to_ktime(t);
+}
+
 /**
  * __timekeeping_inject_sleeptime - Internal function to add sleep interval
  * @delta: pointer to a timespec delta value
@@ -619,7 +669,8 @@ static struct timespec timekeeping_suspend_time;
  * Takes a timespec offset measuring a suspend interval and properly
  * adds the sleep offset to the timekeeping variables.
  */
-static void __timekeeping_inject_sleeptime(struct timespec *delta)
+static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
+                                                       struct timespec *delta)
 {
        if (!timespec_valid(delta)) {
                printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid "
@@ -627,11 +678,9 @@ static void __timekeeping_inject_sleeptime(struct timespec *delta)
                return;
        }
 
-       timekeeper.xtime = timespec_add(timekeeper.xtime, *delta);
-       timekeeper.wall_to_monotonic =
-                       timespec_sub(timekeeper.wall_to_monotonic, *delta);
-       timekeeper.total_sleep_time = timespec_add(
-                                       timekeeper.total_sleep_time, *delta);
+       tk_xtime_add(tk, delta);
+       tk->wall_to_monotonic = timespec_sub(tk->wall_to_monotonic, *delta);
+       update_sleep_time(timespec_add(tk->total_sleep_time, *delta));
 }
 
 
@@ -657,11 +706,11 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
 
        write_seqlock_irqsave(&timekeeper.lock, flags);
 
-       timekeeping_forward_now();
+       timekeeping_forward_now(&timekeeper);
 
-       __timekeeping_inject_sleeptime(delta);
+       __timekeeping_inject_sleeptime(&timekeeper, delta);
 
-       timekeeping_update(true);
+       timekeeping_update(&timekeeper, true);
 
        write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
@@ -690,12 +739,13 @@ static void timekeeping_resume(void)
 
        if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
                ts = timespec_sub(ts, timekeeping_suspend_time);
-               __timekeeping_inject_sleeptime(&ts);
+               __timekeeping_inject_sleeptime(&timekeeper, &ts);
        }
        /* re-base the last cycle value */
        timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
        timekeeper.ntp_error = 0;
        timekeeping_suspended = 0;
+       timekeeping_update(&timekeeper, false);
        write_sequnlock_irqrestore(&timekeeper.lock, flags);
 
        touch_softlockup_watchdog();
@@ -715,7 +765,7 @@ static int timekeeping_suspend(void)
        read_persistent_clock(&timekeeping_suspend_time);
 
        write_seqlock_irqsave(&timekeeper.lock, flags);
-       timekeeping_forward_now();
+       timekeeping_forward_now(&timekeeper);
        timekeeping_suspended = 1;
 
        /*
@@ -724,7 +774,7 @@ static int timekeeping_suspend(void)
         * try to compensate so the difference in system time
         * and persistent_clock time stays close to constant.
         */
-       delta = timespec_sub(timekeeper.xtime, timekeeping_suspend_time);
+       delta = timespec_sub(tk_xtime(&timekeeper), timekeeping_suspend_time);
        delta_delta = timespec_sub(delta, old_delta);
        if (abs(delta_delta.tv_sec)  >= 2) {
                /*
@@ -763,7 +813,8 @@ device_initcall(timekeeping_init_ops);
  * If the error is already larger, we look ahead even further
  * to compensate for late or lost adjustments.
  */
-static __always_inline int timekeeping_bigadjust(s64 error, s64 *interval,
+static __always_inline int timekeeping_bigadjust(struct timekeeper *tk,
+                                                s64 error, s64 *interval,
                                                 s64 *offset)
 {
        s64 tick_error, i;
@@ -779,7 +830,7 @@ static __always_inline int timekeeping_bigadjust(s64 error, s64 *interval,
         * here.  This is tuned so that an error of about 1 msec is adjusted
         * within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
         */
-       error2 = timekeeper.ntp_error >> (NTP_SCALE_SHIFT + 22 - 2 * SHIFT_HZ);
+       error2 = tk->ntp_error >> (NTP_SCALE_SHIFT + 22 - 2 * SHIFT_HZ);
        error2 = abs(error2);
        for (look_ahead = 0; error2 > 0; look_ahead++)
                error2 >>= 2;
@@ -788,8 +839,8 @@ static __always_inline int timekeeping_bigadjust(s64 error, s64 *interval,
         * Now calculate the error in (1 << look_ahead) ticks, but first
         * remove the single look ahead already included in the error.
         */
-       tick_error = ntp_tick_length() >> (timekeeper.ntp_error_shift + 1);
-       tick_error -= timekeeper.xtime_interval >> 1;
+       tick_error = ntp_tick_length() >> (tk->ntp_error_shift + 1);
+       tick_error -= tk->xtime_interval >> 1;
        error = ((error - tick_error) >> look_ahead) + tick_error;
 
        /* Finally calculate the adjustment shift value.  */
@@ -814,9 +865,9 @@ static __always_inline int timekeeping_bigadjust(s64 error, s64 *interval,
  * this is optimized for the most common adjustments of -1,0,1,
  * for other values we can do a bit more work.
  */
-static void timekeeping_adjust(s64 offset)
+static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
 {
-       s64 error, interval = timekeeper.cycle_interval;
+       s64 error, interval = tk->cycle_interval;
        int adj;
 
        /*
@@ -832,7 +883,7 @@ static void timekeeping_adjust(s64 offset)
         *
         * Note: It does not "save" on aggravation when reading the code.
         */
-       error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1);
+       error = tk->ntp_error >> (tk->ntp_error_shift - 1);
        if (error > interval) {
                /*
                 * We now divide error by 4(via shift), which checks if
@@ -854,7 +905,8 @@ static void timekeeping_adjust(s64 offset)
                if (likely(error <= interval))
                        adj = 1;
                else
-                       adj = timekeeping_bigadjust(error, &interval, &offset);
+                       adj = timekeeping_bigadjust(tk, error, &interval,
+                                                       &offset);
        } else if (error < -interval) {
                /* See comment above, this is just switched for the negative */
                error >>= 2;
@@ -863,18 +915,17 @@ static void timekeeping_adjust(s64 offset)
                        interval = -interval;
                        offset = -offset;
                } else
-                       adj = timekeeping_bigadjust(error, &interval, &offset);
-       } else /* No adjustment needed */
+                       adj = timekeeping_bigadjust(tk, error, &interval,
+                                                       &offset);
+       } else
                return;
 
-       if (unlikely(timekeeper.clock->maxadj &&
-                       (timekeeper.mult + adj >
-                       timekeeper.clock->mult + timekeeper.clock->maxadj))) {
+       if (unlikely(tk->clock->maxadj &&
+               (tk->mult + adj > tk->clock->mult + tk->clock->maxadj))) {
                printk_once(KERN_WARNING
                        "Adjusting %s more than 11%% (%ld vs %ld)\n",
-                       timekeeper.clock->name, (long)timekeeper.mult + adj,
-                       (long)timekeeper.clock->mult +
-                               timekeeper.clock->maxadj);
+                       tk->clock->name, (long)tk->mult + adj,
+                       (long)tk->clock->mult + tk->clock->maxadj);
        }
        /*
         * So the following can be confusing.
@@ -925,11 +976,60 @@ static void timekeeping_adjust(s64 offset)
         *
         * XXX - TODO: Doc ntp_error calculation.
         */
-       timekeeper.mult += adj;
-       timekeeper.xtime_interval += interval;
-       timekeeper.xtime_nsec -= offset;
-       timekeeper.ntp_error -= (interval - offset) <<
-                               timekeeper.ntp_error_shift;
+       tk->mult += adj;
+       tk->xtime_interval += interval;
+       tk->xtime_nsec -= offset;
+       tk->ntp_error -= (interval - offset) << tk->ntp_error_shift;
+
+       /*
+        * It may be possible that when we entered this function, xtime_nsec
+        * was very small.  Further, if we're slightly speeding the clocksource
+        * in the code above, its possible the required corrective factor to
+        * xtime_nsec could cause it to underflow.
+        *
+        * Now, since we already accumulated the second, cannot simply roll
+        * the accumulated second back, since the NTP subsystem has been
+        * notified via second_overflow. So instead we push xtime_nsec forward
+        * by the amount we underflowed, and add that amount into the error.
+        *
+        * We'll correct this error next time through this function, when
+        * xtime_nsec is not as small.
+        */
+       if (unlikely((s64)tk->xtime_nsec < 0)) {
+               s64 neg = -(s64)tk->xtime_nsec;
+               tk->xtime_nsec = 0;
+               tk->ntp_error += neg << tk->ntp_error_shift;
+       }
+
+}
+
+
+/**
+ * accumulate_nsecs_to_secs - Accumulates nsecs into secs
+ *
+ * Helper function that accumulates a the nsecs greater then a second
+ * from the xtime_nsec field to the xtime_secs field.
+ * It also calls into the NTP code to handle leapsecond processing.
+ *
+ */
+static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
+{
+       u64 nsecps = (u64)NSEC_PER_SEC << tk->shift;
+
+       while (tk->xtime_nsec >= nsecps) {
+               int leap;
+
+               tk->xtime_nsec -= nsecps;
+               tk->xtime_sec++;
+
+               /* Figure out if its a leap sec and apply if needed */
+               leap = second_overflow(tk->xtime_sec);
+               tk->xtime_sec += leap;
+               tk->wall_to_monotonic.tv_sec -= leap;
+               if (leap)
+                       clock_was_set_delayed();
+
+       }
 }
 
 
@@ -942,44 +1042,36 @@ static void timekeeping_adjust(s64 offset)
  *
  * Returns the unconsumed cycles.
  */
-static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
+static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
+                                               u32 shift)
 {
-       u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
        u64 raw_nsecs;
 
-       /* If the offset is smaller than a shifted interval, do nothing */
-       if (offset < timekeeper.cycle_interval<<shift)
+       /* If the offset is smaller then a shifted interval, do nothing */
+       if (offset < tk->cycle_interval<<shift)
                return offset;
 
        /* Accumulate one shifted interval */
-       offset -= timekeeper.cycle_interval << shift;
-       timekeeper.clock->cycle_last += timekeeper.cycle_interval << shift;
+       offset -= tk->cycle_interval << shift;
+       tk->clock->cycle_last += tk->cycle_interval << shift;
 
-       timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
-       while (timekeeper.xtime_nsec >= nsecps) {
-               int leap;
-               timekeeper.xtime_nsec -= nsecps;
-               timekeeper.xtime.tv_sec++;
-               leap = second_overflow(timekeeper.xtime.tv_sec);
-               timekeeper.xtime.tv_sec += leap;
-               timekeeper.wall_to_monotonic.tv_sec -= leap;
-       }
+       tk->xtime_nsec += tk->xtime_interval << shift;
+       accumulate_nsecs_to_secs(tk);
 
        /* Accumulate raw time */
-       raw_nsecs = timekeeper.raw_interval << shift;
-       raw_nsecs += timekeeper.raw_time.tv_nsec;
+       raw_nsecs = tk->raw_interval << shift;
+       raw_nsecs += tk->raw_time.tv_nsec;
        if (raw_nsecs >= NSEC_PER_SEC) {
                u64 raw_secs = raw_nsecs;
                raw_nsecs = do_div(raw_secs, NSEC_PER_SEC);
-               timekeeper.raw_time.tv_sec += raw_secs;
+               tk->raw_time.tv_sec += raw_secs;
        }
-       timekeeper.raw_time.tv_nsec = raw_nsecs;
+       tk->raw_time.tv_nsec = raw_nsecs;
 
        /* Accumulate error between NTP and clock interval */
-       timekeeper.ntp_error += ntp_tick_length() << shift;
-       timekeeper.ntp_error -=
-           (timekeeper.xtime_interval + timekeeper.xtime_remainder) <<
-                               (timekeeper.ntp_error_shift + shift);
+       tk->ntp_error += ntp_tick_length() << shift;
+       tk->ntp_error -= (tk->xtime_interval + tk->xtime_remainder) <<
+                                               (tk->ntp_error_shift + shift);
 
        return offset;
 }
@@ -995,6 +1087,7 @@ static void update_wall_time(void)
        cycle_t offset;
        int shift = 0, maxshift;
        unsigned long flags;
+       s64 remainder;
 
        write_seqlock_irqsave(&timekeeper.lock, flags);
 
@@ -1009,8 +1102,6 @@ static void update_wall_time(void)
 #else
        offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
 #endif
-       timekeeper.xtime_nsec = (s64)timekeeper.xtime.tv_nsec <<
-                                               timekeeper.shift;
 
        /*
         * With NO_HZ we may have to accumulate many cycle_intervals
@@ -1026,62 +1117,36 @@ static void update_wall_time(void)
        maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
        shift = min(shift, maxshift);
        while (offset >= timekeeper.cycle_interval) {
-               offset = logarithmic_accumulation(offset, shift);
+               offset = logarithmic_accumulation(&timekeeper, offset, shift);
                if(offset < timekeeper.cycle_interval<<shift)
                        shift--;
        }
 
        /* correct the clock when NTP error is too big */
-       timekeeping_adjust(offset);
-
-       /*
-        * Since in the loop above, we accumulate any amount of time
-        * in xtime_nsec over a second into xtime.tv_sec, its possible for
-        * xtime_nsec to be fairly small after the loop. Further, if we're
-        * slightly speeding the clocksource up in timekeeping_adjust(),
-        * its possible the required corrective factor to xtime_nsec could
-        * cause it to underflow.
-        *
-        * Now, we cannot simply roll the accumulated second back, since
-        * the NTP subsystem has been notified via second_overflow. So
-        * instead we push xtime_nsec forward by the amount we underflowed,
-        * and add that amount into the error.
-        *
-        * We'll correct this error next time through this function, when
-        * xtime_nsec is not as small.
-        */
-       if (unlikely((s64)timekeeper.xtime_nsec < 0)) {
-               s64 neg = -(s64)timekeeper.xtime_nsec;
-               timekeeper.xtime_nsec = 0;
-               timekeeper.ntp_error += neg << timekeeper.ntp_error_shift;
-       }
+       timekeeping_adjust(&timekeeper, offset);
 
 
        /*
-        * Store full nanoseconds into xtime after rounding it up and
-        * add the remainder to the error difference.
-        */
-       timekeeper.xtime.tv_nsec = ((s64)timekeeper.xtime_nsec >>
-                                               timekeeper.shift) + 1;
-       timekeeper.xtime_nsec -= (s64)timekeeper.xtime.tv_nsec <<
-                                               timekeeper.shift;
-       timekeeper.ntp_error += timekeeper.xtime_nsec <<
-                               timekeeper.ntp_error_shift;
+       * Store only full nanoseconds into xtime_nsec after rounding
+       * it up and add the remainder to the error difference.
+       * XXX - This is necessary to avoid small 1ns inconsistnecies caused
+       * by truncating the remainder in vsyscalls. However, it causes
+       * additional work to be done in timekeeping_adjust(). Once
+       * the vsyscall implementations are converted to use xtime_nsec
+       * (shifted nanoseconds), this can be killed.
+       */
+       remainder = timekeeper.xtime_nsec & ((1 << timekeeper.shift) - 1);
+       timekeeper.xtime_nsec -= remainder;
+       timekeeper.xtime_nsec += 1 << timekeeper.shift;
+       timekeeper.ntp_error += remainder << timekeeper.ntp_error_shift;
 
        /*
         * Finally, make sure that after the rounding
-        * xtime.tv_nsec isn't larger than NSEC_PER_SEC
+        * xtime_nsec isn't larger than NSEC_PER_SEC
         */
-       if (unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC)) {
-               int leap;
-               timekeeper.xtime.tv_nsec -= NSEC_PER_SEC;
-               timekeeper.xtime.tv_sec++;
-               leap = second_overflow(timekeeper.xtime.tv_sec);
-               timekeeper.xtime.tv_sec += leap;
-               timekeeper.wall_to_monotonic.tv_sec -= leap;
-       }
+       accumulate_nsecs_to_secs(&timekeeper);
 
-       timekeeping_update(false);
+       timekeeping_update(&timekeeper, false);
 
 out:
        write_sequnlock_irqrestore(&timekeeper.lock, flags);
@@ -1126,21 +1191,20 @@ void get_monotonic_boottime(struct timespec *ts)
 {
        struct timespec tomono, sleep;
        unsigned int seq;
-       s64 nsecs;
 
        WARN_ON(timekeeping_suspended);
 
        do {
                seq = read_seqbegin(&timekeeper.lock);
-               *ts = timekeeper.xtime;
+               ts->tv_sec = timekeeper.xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
                tomono = timekeeper.wall_to_monotonic;
                sleep = timekeeper.total_sleep_time;
-               nsecs = timekeeping_get_ns();
 
        } while (read_seqretry(&timekeeper.lock, seq));
 
        set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
-                       ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs);
+                       ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(get_monotonic_boottime);
 
@@ -1173,13 +1237,13 @@ EXPORT_SYMBOL_GPL(monotonic_to_bootbased);
 
 unsigned long get_seconds(void)
 {
-       return timekeeper.xtime.tv_sec;
+       return timekeeper.xtime_sec;
 }
 EXPORT_SYMBOL(get_seconds);
 
 struct timespec __current_kernel_time(void)
 {
-       return timekeeper.xtime;
+       return tk_xtime(&timekeeper);
 }
 
 struct timespec current_kernel_time(void)
@@ -1190,7 +1254,7 @@ struct timespec current_kernel_time(void)
        do {
                seq = read_seqbegin(&timekeeper.lock);
 
-               now = timekeeper.xtime;
+               now = tk_xtime(&timekeeper);
        } while (read_seqretry(&timekeeper.lock, seq));
 
        return now;
@@ -1205,7 +1269,7 @@ struct timespec get_monotonic_coarse(void)
        do {
                seq = read_seqbegin(&timekeeper.lock);
 
-               now = timekeeper.xtime;
+               now = tk_xtime(&timekeeper);
                mono = timekeeper.wall_to_monotonic;
        } while (read_seqretry(&timekeeper.lock, seq));
 
@@ -1240,12 +1304,43 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
 
        do {
                seq = read_seqbegin(&timekeeper.lock);
-               *xtim = timekeeper.xtime;
+               *xtim = tk_xtime(&timekeeper);
                *wtom = timekeeper.wall_to_monotonic;
                *sleep = timekeeper.total_sleep_time;
        } while (read_seqretry(&timekeeper.lock, seq));
 }
 
+#ifdef CONFIG_HIGH_RES_TIMERS
+/**
+ * ktime_get_update_offsets - hrtimer helper
+ * @offs_real: pointer to storage for monotonic -> realtime offset
+ * @offs_boot: pointer to storage for monotonic -> boottime offset
+ *
+ * Returns current monotonic time and updates the offsets
+ * Called from hrtimer_interupt() or retrigger_next_event()
+ */
+ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
+{
+       ktime_t now;
+       unsigned int seq;
+       u64 secs, nsecs;
+
+       do {
+               seq = read_seqbegin(&timekeeper.lock);
+
+               secs = timekeeper.xtime_sec;
+               nsecs = timekeeping_get_ns(&timekeeper);
+
+               *offs_real = timekeeper.offs_real;
+               *offs_boot = timekeeper.offs_boot;
+       } while (read_seqretry(&timekeeper.lock, seq));
+
+       now = ktime_add_ns(ktime_set(secs, 0), nsecs);
+       now = ktime_sub(now, *offs_real);
+       return now;
+}
+#endif
+
 /**
  * ktime_get_monotonic_offset() - get wall_to_monotonic in ktime_t format
  */
index 3258455549f421d3b65e0d085929541f672b29b0..af5a7e9f164b53b3bedbc32ac0b516c7091760db 100644 (file)
@@ -167,7 +167,7 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
        {
                struct tick_sched *ts = tick_get_tick_sched(cpu);
                P(nohz_mode);
-               P_ns(idle_tick);
+               P_ns(last_tick);
                P(tick_stopped);
                P(idle_jiffies);
                P(idle_calls);
@@ -259,7 +259,7 @@ static int timer_list_show(struct seq_file *m, void *v)
        u64 now = ktime_to_ns(ktime_get());
        int cpu;
 
-       SEQ_printf(m, "Timer List Version: v0.6\n");
+       SEQ_printf(m, "Timer List Version: v0.7\n");
        SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
        SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
 
index 6ec7e7e0db435d722cecd601090ca4a8b3dc994a..a61c09374ebab1fdba0bdd370b56cf70018de62d 100644 (file)
@@ -77,6 +77,7 @@ struct tvec_base {
        struct timer_list *running_timer;
        unsigned long timer_jiffies;
        unsigned long next_timer;
+       unsigned long active_timers;
        struct tvec_root tv1;
        struct tvec tv2;
        struct tvec tv3;
@@ -330,7 +331,8 @@ void set_timer_slack(struct timer_list *timer, int slack_hz)
 }
 EXPORT_SYMBOL_GPL(set_timer_slack);
 
-static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
+static void
+__internal_add_timer(struct tvec_base *base, struct timer_list *timer)
 {
        unsigned long expires = timer->expires;
        unsigned long idx = expires - base->timer_jiffies;
@@ -372,6 +374,19 @@ static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
        list_add_tail(&timer->entry, vec);
 }
 
+static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
+{
+       __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))
+                       base->next_timer = timer->expires;
+               base->active_timers++;
+       }
+}
+
 #ifdef CONFIG_TIMER_STATS
 void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
 {
@@ -654,8 +669,7 @@ void init_timer_deferrable_key(struct timer_list *timer,
 }
 EXPORT_SYMBOL(init_timer_deferrable_key);
 
-static inline void detach_timer(struct timer_list *timer,
-                               int clear_pending)
+static inline void detach_timer(struct timer_list *timer, bool clear_pending)
 {
        struct list_head *entry = &timer->entry;
 
@@ -667,6 +681,29 @@ static inline void detach_timer(struct timer_list *timer,
        entry->prev = LIST_POISON2;
 }
 
+static inline void
+detach_expired_timer(struct timer_list *timer, struct tvec_base *base)
+{
+       detach_timer(timer, true);
+       if (!tbase_get_deferrable(timer->base))
+               timer->base->active_timers--;
+}
+
+static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
+                            bool clear_pending)
+{
+       if (!timer_pending(timer))
+               return 0;
+
+       detach_timer(timer, clear_pending);
+       if (!tbase_get_deferrable(timer->base)) {
+               timer->base->active_timers--;
+               if (timer->expires == base->next_timer)
+                       base->next_timer = base->timer_jiffies;
+       }
+       return 1;
+}
+
 /*
  * We are using hashed locking: holding per_cpu(tvec_bases).lock
  * means that all timers which are tied to this base via timer->base are
@@ -712,16 +749,9 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
 
        base = lock_timer_base(timer, &flags);
 
-       if (timer_pending(timer)) {
-               detach_timer(timer, 0);
-               if (timer->expires == base->next_timer &&
-                   !tbase_get_deferrable(timer->base))
-                       base->next_timer = base->timer_jiffies;
-               ret = 1;
-       } else {
-               if (pending_only)
-                       goto out_unlock;
-       }
+       ret = detach_if_pending(timer, base, false);
+       if (!ret && pending_only)
+               goto out_unlock;
 
        debug_activate(timer, expires);
 
@@ -752,9 +782,6 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
        }
 
        timer->expires = expires;
-       if (time_before(timer->expires, base->next_timer) &&
-           !tbase_get_deferrable(timer->base))
-               base->next_timer = timer->expires;
        internal_add_timer(base, timer);
 
 out_unlock:
@@ -920,9 +947,6 @@ void add_timer_on(struct timer_list *timer, int cpu)
        spin_lock_irqsave(&base->lock, flags);
        timer_set_base(timer, base);
        debug_activate(timer, timer->expires);
-       if (time_before(timer->expires, base->next_timer) &&
-           !tbase_get_deferrable(timer->base))
-               base->next_timer = timer->expires;
        internal_add_timer(base, timer);
        /*
         * Check whether the other CPU is idle and needs to be
@@ -959,13 +983,7 @@ int del_timer(struct timer_list *timer)
        timer_stats_timer_clear_start_info(timer);
        if (timer_pending(timer)) {
                base = lock_timer_base(timer, &flags);
-               if (timer_pending(timer)) {
-                       detach_timer(timer, 1);
-                       if (timer->expires == base->next_timer &&
-                           !tbase_get_deferrable(timer->base))
-                               base->next_timer = base->timer_jiffies;
-                       ret = 1;
-               }
+               ret = detach_if_pending(timer, base, true);
                spin_unlock_irqrestore(&base->lock, flags);
        }
 
@@ -990,19 +1008,10 @@ int try_to_del_timer_sync(struct timer_list *timer)
 
        base = lock_timer_base(timer, &flags);
 
-       if (base->running_timer == timer)
-               goto out;
-
-       timer_stats_timer_clear_start_info(timer);
-       ret = 0;
-       if (timer_pending(timer)) {
-               detach_timer(timer, 1);
-               if (timer->expires == base->next_timer &&
-                   !tbase_get_deferrable(timer->base))
-                       base->next_timer = base->timer_jiffies;
-               ret = 1;
+       if (base->running_timer != timer) {
+               timer_stats_timer_clear_start_info(timer);
+               ret = detach_if_pending(timer, base, true);
        }
-out:
        spin_unlock_irqrestore(&base->lock, flags);
 
        return ret;
@@ -1089,7 +1098,8 @@ static int cascade(struct tvec_base *base, struct tvec *tv, int index)
         */
        list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
                BUG_ON(tbase_get_base(timer->base) != base);
-               internal_add_timer(base, timer);
+               /* No accounting, while moving them */
+               __internal_add_timer(base, timer);
        }
 
        return index;
@@ -1178,7 +1188,7 @@ static inline void __run_timers(struct tvec_base *base)
                        timer_stats_account_timer(timer);
 
                        base->running_timer = timer;
-                       detach_timer(timer, 1);
+                       detach_expired_timer(timer, base);
 
                        spin_unlock_irq(&base->lock);
                        call_timer_fn(timer, fn, data);
@@ -1316,18 +1326,21 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
 unsigned long get_next_timer_interrupt(unsigned long now)
 {
        struct tvec_base *base = __this_cpu_read(tvec_bases);
-       unsigned long expires;
+       unsigned long expires = now + NEXT_TIMER_MAX_DELTA;
 
        /*
         * Pretend that there is no timer pending if the cpu is offline.
         * Possible pending timers will be migrated later to an active cpu.
         */
        if (cpu_is_offline(smp_processor_id()))
-               return now + NEXT_TIMER_MAX_DELTA;
+               return expires;
+
        spin_lock(&base->lock);
-       if (time_before_eq(base->next_timer, base->timer_jiffies))
-               base->next_timer = __next_timer_interrupt(base);
-       expires = base->next_timer;
+       if (base->active_timers) {
+               if (time_before_eq(base->next_timer, base->timer_jiffies))
+                       base->next_timer = __next_timer_interrupt(base);
+               expires = base->next_timer;
+       }
        spin_unlock(&base->lock);
 
        if (time_before_eq(expires, now))
@@ -1704,6 +1717,7 @@ static int __cpuinit init_timers_cpu(int cpu)
 
        base->timer_jiffies = jiffies;
        base->next_timer = base->timer_jiffies;
+       base->active_timers = 0;
        return 0;
 }
 
@@ -1714,11 +1728,9 @@ static void migrate_timer_list(struct tvec_base *new_base, struct list_head *hea
 
        while (!list_empty(head)) {
                timer = list_first_entry(head, struct timer_list, entry);
-               detach_timer(timer, 0);
+               /* We ignore the accounting on the dying cpu */
+               detach_timer(timer, false);
                timer_set_base(timer, new_base);
-               if (time_before(timer->expires, new_base->next_timer) &&
-                   !tbase_get_deferrable(timer->base))
-                       new_base->next_timer = timer->expires;
                internal_add_timer(new_base, timer);
        }
 }
index a008663d86c8e740c64c1cc26977a7a199917b9b..b4f20fba09fcc77dc571bdf718bfd04adfb29897 100644 (file)
@@ -312,7 +312,7 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list,
 
 static int __register_ftrace_function(struct ftrace_ops *ops)
 {
-       if (ftrace_disabled)
+       if (unlikely(ftrace_disabled))
                return -ENODEV;
 
        if (FTRACE_WARN_ON(ops == &global_ops))
@@ -4299,16 +4299,12 @@ int register_ftrace_function(struct ftrace_ops *ops)
 
        mutex_lock(&ftrace_lock);
 
-       if (unlikely(ftrace_disabled))
-               goto out_unlock;
-
        ret = __register_ftrace_function(ops);
        if (!ret)
                ret = ftrace_startup(ops, 0);
 
-
- out_unlock:
        mutex_unlock(&ftrace_lock);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(register_ftrace_function);
index 1d0f6a8a0e5e83680c0df3b28836a5f6a2103a39..49491fa7daa2d35546a6e5ba46d73103594c384e 100644 (file)
@@ -1075,6 +1075,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu)
        rb_init_page(bpage->page);
 
        INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
+       INIT_LIST_HEAD(&cpu_buffer->new_pages);
 
        ret = rb_allocate_pages(cpu_buffer, nr_pages);
        if (ret < 0)
@@ -1346,10 +1347,9 @@ rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned int nr_pages)
                         * If something was added to this page, it was full
                         * since it is not the tail page. So we deduct the
                         * bytes consumed in ring buffer from here.
-                        * No need to update overruns, since this page is
-                        * deleted from ring buffer and its entries are
-                        * already accounted for.
+                        * Increment overrun to account for the lost events.
                         */
+                       local_add(page_entries, &cpu_buffer->overrun);
                        local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
                }
 
@@ -3239,6 +3239,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
        if (cpu_buffer->commit_page == cpu_buffer->reader_page)
                goto out;
 
+       /* Don't bother swapping if the ring buffer is empty */
+       if (rb_num_of_entries(cpu_buffer) == 0)
+               goto out;
+
        /*
         * Reset the reader page to size zero.
         */
index 49249c28690dbb21b6914e2907b16af56e1094c9..a120f98c4112c15b5d6febf78674c00ec459e18d 100644 (file)
@@ -830,6 +830,8 @@ int register_tracer(struct tracer *type)
                current_trace = saved_tracer;
                if (ret) {
                        printk(KERN_CONT "FAILED!\n");
+                       /* Add the warning after printing 'FAILED' */
+                       WARN_ON(1);
                        goto out;
                }
                /* Only reset on passing, to avoid touching corrupted buffers */
@@ -1708,9 +1710,11 @@ EXPORT_SYMBOL_GPL(trace_vprintk);
 
 static void trace_iterator_increment(struct trace_iterator *iter)
 {
+       struct ring_buffer_iter *buf_iter = trace_buffer_iter(iter, iter->cpu);
+
        iter->idx++;
-       if (iter->buffer_iter[iter->cpu])
-               ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
+       if (buf_iter)
+               ring_buffer_read(buf_iter, NULL);
 }
 
 static struct trace_entry *
@@ -1718,7 +1722,7 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts,
                unsigned long *lost_events)
 {
        struct ring_buffer_event *event;
-       struct ring_buffer_iter *buf_iter = iter->buffer_iter[cpu];
+       struct ring_buffer_iter *buf_iter = trace_buffer_iter(iter, cpu);
 
        if (buf_iter)
                event = ring_buffer_iter_peek(buf_iter, ts);
@@ -1856,10 +1860,10 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
 
        tr->data[cpu]->skipped_entries = 0;
 
-       if (!iter->buffer_iter[cpu])
+       buf_iter = trace_buffer_iter(iter, cpu);
+       if (!buf_iter)
                return;
 
-       buf_iter = iter->buffer_iter[cpu];
        ring_buffer_iter_reset(buf_iter);
 
        /*
@@ -2205,13 +2209,15 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
 
 int trace_empty(struct trace_iterator *iter)
 {
+       struct ring_buffer_iter *buf_iter;
        int cpu;
 
        /* If we are looking at one CPU buffer, only check that one */
        if (iter->cpu_file != TRACE_PIPE_ALL_CPU) {
                cpu = iter->cpu_file;
-               if (iter->buffer_iter[cpu]) {
-                       if (!ring_buffer_iter_empty(iter->buffer_iter[cpu]))
+               buf_iter = trace_buffer_iter(iter, cpu);
+               if (buf_iter) {
+                       if (!ring_buffer_iter_empty(buf_iter))
                                return 0;
                } else {
                        if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
@@ -2221,8 +2227,9 @@ int trace_empty(struct trace_iterator *iter)
        }
 
        for_each_tracing_cpu(cpu) {
-               if (iter->buffer_iter[cpu]) {
-                       if (!ring_buffer_iter_empty(iter->buffer_iter[cpu]))
+               buf_iter = trace_buffer_iter(iter, cpu);
+               if (buf_iter) {
+                       if (!ring_buffer_iter_empty(buf_iter))
                                return 0;
                } else {
                        if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
@@ -2381,6 +2388,11 @@ __tracing_open(struct inode *inode, struct file *file)
        if (!iter)
                return ERR_PTR(-ENOMEM);
 
+       iter->buffer_iter = kzalloc(sizeof(*iter->buffer_iter) * num_possible_cpus(),
+                                   GFP_KERNEL);
+       if (!iter->buffer_iter)
+               goto release;
+
        /*
         * We make a copy of the current tracer to avoid concurrent
         * changes on it while we are reading.
@@ -2441,6 +2453,8 @@ __tracing_open(struct inode *inode, struct file *file)
  fail:
        mutex_unlock(&trace_types_lock);
        kfree(iter->trace);
+       kfree(iter->buffer_iter);
+release:
        seq_release_private(inode, file);
        return ERR_PTR(-ENOMEM);
 }
@@ -2481,6 +2495,7 @@ static int tracing_release(struct inode *inode, struct file *file)
        mutex_destroy(&iter->mutex);
        free_cpumask_var(iter->started);
        kfree(iter->trace);
+       kfree(iter->buffer_iter);
        seq_release_private(inode, file);
        return 0;
 }
@@ -3609,6 +3624,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
                .pages          = pages_def,
                .partial        = partial_def,
                .nr_pages       = 0, /* This gets updated below. */
+               .nr_pages_max   = PIPE_DEF_BUFFERS,
                .flags          = flags,
                .ops            = &tracing_pipe_buf_ops,
                .spd_release    = tracing_spd_release_pipe,
@@ -3680,7 +3696,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
 
        ret = splice_to_pipe(pipe, &spd);
 out:
-       splice_shrink_spd(pipe, &spd);
+       splice_shrink_spd(&spd);
        return ret;
 
 out_err:
@@ -4231,6 +4247,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
        struct splice_pipe_desc spd = {
                .pages          = pages_def,
                .partial        = partial_def,
+               .nr_pages_max   = PIPE_DEF_BUFFERS,
                .flags          = flags,
                .ops            = &buffer_pipe_buf_ops,
                .spd_release    = buffer_spd_release,
@@ -4318,7 +4335,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
        }
 
        ret = splice_to_pipe(pipe, &spd);
-       splice_shrink_spd(pipe, &spd);
+       splice_shrink_spd(&spd);
 out:
        return ret;
 }
index 5aec220d2de0de314b4d292eaaeba43c60f34a1a..55e1f7f0db126edf4bbcbe07245a9558b1030bec 100644 (file)
@@ -317,6 +317,14 @@ struct tracer {
 
 #define TRACE_PIPE_ALL_CPU     -1
 
+static inline struct ring_buffer_iter *
+trace_buffer_iter(struct trace_iterator *iter, int cpu)
+{
+       if (iter->buffer_iter && iter->buffer_iter[cpu])
+               return iter->buffer_iter[cpu];
+       return NULL;
+}
+
 int tracer_init(struct tracer *t, struct trace_array *tr);
 int tracing_is_enabled(void);
 void trace_wake_up(void);
index a7d2a4c653d8d893f51652c8cd599bf780359f45..ce27c8ba8d318ffa6337f231e12a680f6deb7720 100644 (file)
@@ -538,7 +538,7 @@ get_return_for_leaf(struct trace_iterator *iter,
                next = &data->ret;
        } else {
 
-               ring_iter = iter->buffer_iter[iter->cpu];
+               ring_iter = trace_buffer_iter(iter, iter->cpu);
 
                /* First peek to compare current entry and the next one */
                if (ring_iter)
index df611a0e76c55b0d47febf4312874e839114bb13..123b189c732c4142965252d80e9d49745127fe39 100644 (file)
@@ -1325,4 +1325,4 @@ __init static int init_events(void)
 
        return 0;
 }
-device_initcall(init_events);
+early_initcall(init_events);
index 518aea714d21d9dea1c7d52b0cf6878482ca5d82..66ce414891330964aacb48dee8079138034cad3d 100644 (file)
@@ -78,7 +78,7 @@ static LIST_HEAD(free_entries);
 static DEFINE_SPINLOCK(free_entries_lock);
 
 /* Global disable flag - will be set in case of an error */
-static bool global_disable __read_mostly;
+static u32 global_disable __read_mostly;
 
 /* Global error count */
 static u32 error_count;
@@ -657,7 +657,7 @@ static int dma_debug_fs_init(void)
 
        global_disable_dent = debugfs_create_bool("disabled", 0444,
                        dma_debug_dent,
-                       (u32 *)&global_disable);
+                       &global_disable);
        if (!global_disable_dent)
                goto out_err;
 
index 23a5e031cd8bc43605655da59bce57eadb3304b8..c24c2f7e296fa15e5431ef7dc4a31f8551e37c15 100644 (file)
@@ -87,12 +87,10 @@ void __list_add_rcu(struct list_head *new,
                    struct list_head *prev, struct list_head *next)
 {
        WARN(next->prev != prev,
-               "list_add_rcu corruption. next->prev should be "
-               "prev (%p), but was %p. (next=%p).\n",
+               "list_add_rcu corruption. next->prev should be prev (%p), but was %p. (next=%p).\n",
                prev, next->prev, next);
        WARN(prev->next != next,
-               "list_add_rcu corruption. prev->next should be "
-               "next (%p), but was %p. (prev=%p).\n",
+               "list_add_rcu corruption. prev->next should be next (%p), but was %p. (prev=%p).\n",
                next, prev->next, prev);
        new->next = next;
        new->prev = prev;
index ec4fcb7a56c8975492d656940906af6153136e51..bcb63ac48cc5e0d20eb7d1359b8d6d79a7358ac0 100644 (file)
@@ -698,7 +698,7 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align,
        return ___alloc_bootmem(size, align, goal, limit);
 }
 
-static void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
+void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
                                unsigned long size, unsigned long align,
                                unsigned long goal, unsigned long limit)
 {
@@ -710,6 +710,10 @@ again:
        if (ptr)
                return ptr;
 
+       /* do not panic in alloc_bootmem_bdata() */
+       if (limit && goal + size > limit)
+               limit = 0;
+
        ptr = alloc_bootmem_bdata(pgdat->bdata, size, align, goal, limit);
        if (ptr)
                return ptr;
index 7ea259d82a998c0397e976216ac861576e638100..2f42d952853970b5dd1f95a149d8750e7d570357 100644 (file)
@@ -701,8 +701,11 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                if (err) {
                        putback_lru_pages(&cc->migratepages);
                        cc->nr_migratepages = 0;
+                       if (err == -ENOMEM) {
+                               ret = COMPACT_PARTIAL;
+                               goto out;
+                       }
                }
-
        }
 
 out:
index deff1b64a08c36ef4857590e9913717488953014..14d260fa0d17939a2279c244df91789cd30720e4 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/ksm.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 
 /*
  * Any behaviour which results in changes to the vma->vm_flags needs to
@@ -204,14 +205,16 @@ static long madvise_remove(struct vm_area_struct *vma,
 {
        loff_t offset;
        int error;
+       struct file *f;
 
        *prev = NULL;   /* tell sys_madvise we drop mmap_sem */
 
        if (vma->vm_flags & (VM_LOCKED|VM_NONLINEAR|VM_HUGETLB))
                return -EINVAL;
 
-       if (!vma->vm_file || !vma->vm_file->f_mapping
-               || !vma->vm_file->f_mapping->host) {
+       f = vma->vm_file;
+
+       if (!f || !f->f_mapping || !f->f_mapping->host) {
                        return -EINVAL;
        }
 
@@ -221,11 +224,18 @@ static long madvise_remove(struct vm_area_struct *vma,
        offset = (loff_t)(start - vma->vm_start)
                        + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
 
-       /* filesystem's fallocate may need to take i_mutex */
+       /*
+        * Filesystem's fallocate may need to take i_mutex.  We need to
+        * explicitly grab a reference because the vma (and hence the
+        * vma's reference to the file) can go away as soon as we drop
+        * mmap_sem.
+        */
+       get_file(f);
        up_read(&current->mm->mmap_sem);
-       error = do_fallocate(vma->vm_file,
+       error = do_fallocate(f,
                                FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
                                offset, end - start);
+       fput(f);
        down_read(&current->mm->mmap_sem);
        return error;
 }
index d4382095f8bdcda1493feb7fc835a93432027f42..5cc6731b00ccd05ff2f5b610627a0a2848dc5544 100644 (file)
@@ -143,30 +143,6 @@ phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
                                           MAX_NUMNODES);
 }
 
-/*
- * Free memblock.reserved.regions
- */
-int __init_memblock memblock_free_reserved_regions(void)
-{
-       if (memblock.reserved.regions == memblock_reserved_init_regions)
-               return 0;
-
-       return memblock_free(__pa(memblock.reserved.regions),
-                sizeof(struct memblock_region) * memblock.reserved.max);
-}
-
-/*
- * Reserve memblock.reserved.regions
- */
-int __init_memblock memblock_reserve_reserved_regions(void)
-{
-       if (memblock.reserved.regions == memblock_reserved_init_regions)
-               return 0;
-
-       return memblock_reserve(__pa(memblock.reserved.regions),
-                sizeof(struct memblock_region) * memblock.reserved.max);
-}
-
 static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
 {
        type->total_size -= type->regions[r].size;
@@ -184,6 +160,18 @@ static void __init_memblock memblock_remove_region(struct memblock_type *type, u
        }
 }
 
+phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
+                                       phys_addr_t *addr)
+{
+       if (memblock.reserved.regions == memblock_reserved_init_regions)
+               return 0;
+
+       *addr = __pa(memblock.reserved.regions);
+
+       return PAGE_ALIGN(sizeof(struct memblock_region) *
+                         memblock.reserved.max);
+}
+
 /**
  * memblock_double_array - double the size of the memblock regions array
  * @type: memblock type of the regions array being doubled
@@ -204,6 +192,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
                                                phys_addr_t new_area_size)
 {
        struct memblock_region *new_array, *old_array;
+       phys_addr_t old_alloc_size, new_alloc_size;
        phys_addr_t old_size, new_size, addr;
        int use_slab = slab_is_available();
        int *in_slab;
@@ -217,6 +206,12 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
        /* Calculate new doubled size */
        old_size = type->max * sizeof(struct memblock_region);
        new_size = old_size << 1;
+       /*
+        * We need to allocated new one align to PAGE_SIZE,
+        *   so we can free them completely later.
+        */
+       old_alloc_size = PAGE_ALIGN(old_size);
+       new_alloc_size = PAGE_ALIGN(new_size);
 
        /* Retrieve the slab flag */
        if (type == &memblock.memory)
@@ -245,11 +240,11 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
 
                addr = memblock_find_in_range(new_area_start + new_area_size,
                                                memblock.current_limit,
-                                               new_size, sizeof(phys_addr_t));
+                                               new_alloc_size, PAGE_SIZE);
                if (!addr && new_area_size)
                        addr = memblock_find_in_range(0,
                                        min(new_area_start, memblock.current_limit),
-                                       new_size, sizeof(phys_addr_t));
+                                       new_alloc_size, PAGE_SIZE);
 
                new_array = addr ? __va(addr) : 0;
        }
@@ -279,13 +274,13 @@ static int __init_memblock memblock_double_array(struct memblock_type *type,
                kfree(old_array);
        else if (old_array != memblock_memory_init_regions &&
                 old_array != memblock_reserved_init_regions)
-               memblock_free(__pa(old_array), old_size);
+               memblock_free(__pa(old_array), old_alloc_size);
 
        /* Reserve the new array if that comes from the memblock.
         * Otherwise, we needn't do it
         */
        if (!use_slab)
-               BUG_ON(memblock_reserve(addr, new_size));
+               BUG_ON(memblock_reserve(addr, new_alloc_size));
 
        /* Update slab flag */
        *in_slab = use_slab;
index ab1e7145e2909c8e1a02359fb1e148118c42e1b2..de4ce70584508edfa95eec5827271511052af102 100644 (file)
@@ -345,14 +345,14 @@ static void add_to_kill(struct task_struct *tsk, struct page *p,
  * Also when FAIL is set do a force kill because something went
  * wrong earlier.
  */
-static void kill_procs(struct list_head *to_kill, int doit, int trapno,
+static void kill_procs(struct list_head *to_kill, int forcekill, int trapno,
                          int fail, struct page *page, unsigned long pfn,
                          int flags)
 {
        struct to_kill *tk, *next;
 
        list_for_each_entry_safe (tk, next, to_kill, nd) {
-               if (doit) {
+               if (forcekill) {
                        /*
                         * In case something went wrong with munmapping
                         * make sure the process doesn't catch the
@@ -858,7 +858,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
        struct address_space *mapping;
        LIST_HEAD(tokill);
        int ret;
-       int kill = 1;
+       int kill = 1, forcekill;
        struct page *hpage = compound_head(p);
        struct page *ppage;
 
@@ -888,7 +888,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
         * be called inside page lock (it's recommended but not enforced).
         */
        mapping = page_mapping(hpage);
-       if (!PageDirty(hpage) && mapping &&
+       if (!(flags & MF_MUST_KILL) && !PageDirty(hpage) && mapping &&
            mapping_cap_writeback_dirty(mapping)) {
                if (page_mkclean(hpage)) {
                        SetPageDirty(hpage);
@@ -965,12 +965,14 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
         * Now that the dirty bit has been propagated to the
         * struct page and all unmaps done we can decide if
         * killing is needed or not.  Only kill when the page
-        * was dirty, otherwise the tokill list is merely
+        * was dirty or the process is not restartable,
+        * otherwise the tokill list is merely
         * freed.  When there was a problem unmapping earlier
         * use a more force-full uncatchable kill to prevent
         * any accesses to the poisoned memory.
         */
-       kill_procs(&tokill, !!PageDirty(ppage), trapno,
+       forcekill = PageDirty(ppage) || (flags & MF_MUST_KILL);
+       kill_procs(&tokill, forcekill, trapno,
                      ret != SWAP_SUCCESS, p, pfn, flags);
 
        return ret;
index 0d7e3ec8e0f3cc997b5fa0b422f5fa39caffe413..427bb291dd0fdeeb6db93c86c66df6a6f92c9b28 100644 (file)
@@ -618,7 +618,7 @@ int __ref add_memory(int nid, u64 start, u64 size)
                pgdat = hotadd_new_pgdat(nid, start);
                ret = -ENOMEM;
                if (!pgdat)
-                       goto out;
+                       goto error;
                new_pgdat = 1;
        }
 
index d23415c001bc4c5847986c7659261ca335888382..405573010f99a8b0d877dd980e284979ebd2ec69 100644 (file)
@@ -105,27 +105,35 @@ static void __init __free_pages_memory(unsigned long start, unsigned long end)
                __free_pages_bootmem(pfn_to_page(i), 0);
 }
 
+static unsigned long __init __free_memory_core(phys_addr_t start,
+                                phys_addr_t end)
+{
+       unsigned long start_pfn = PFN_UP(start);
+       unsigned long end_pfn = min_t(unsigned long,
+                                     PFN_DOWN(end), max_low_pfn);
+
+       if (start_pfn > end_pfn)
+               return 0;
+
+       __free_pages_memory(start_pfn, end_pfn);
+
+       return end_pfn - start_pfn;
+}
+
 unsigned long __init free_low_memory_core_early(int nodeid)
 {
        unsigned long count = 0;
-       phys_addr_t start, end;
+       phys_addr_t start, end, size;
        u64 i;
 
-       /* free reserved array temporarily so that it's treated as free area */
-       memblock_free_reserved_regions();
-
-       for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL) {
-               unsigned long start_pfn = PFN_UP(start);
-               unsigned long end_pfn = min_t(unsigned long,
-                                             PFN_DOWN(end), max_low_pfn);
-               if (start_pfn < end_pfn) {
-                       __free_pages_memory(start_pfn, end_pfn);
-                       count += end_pfn - start_pfn;
-               }
-       }
+       for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL)
+               count += __free_memory_core(start, end);
+
+       /* free range that is used for reserved array if we allocate it */
+       size = get_allocated_memblock_reserved_regions_info(&start);
+       if (size)
+               count += __free_memory_core(start, start + size);
 
-       /* put region array back? */
-       memblock_reserve_reserved_regions();
        return count;
 }
 
@@ -274,7 +282,7 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align,
        return ___alloc_bootmem(size, align, goal, limit);
 }
 
-static void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
+void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat,
                                                   unsigned long size,
                                                   unsigned long align,
                                                   unsigned long goal,
index 44030096da631b5f49b4ee1a81d0b9ace59f5c7e..4a4f9219683f63d8594c143fa24f27d4daa6a8ff 100644 (file)
@@ -5635,7 +5635,12 @@ static struct page *
 __alloc_contig_migrate_alloc(struct page *page, unsigned long private,
                             int **resultp)
 {
-       return alloc_page(GFP_HIGHUSER_MOVABLE);
+       gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
+
+       if (PageHighMem(page))
+               gfp_mask |= __GFP_HIGHMEM;
+
+       return alloc_page(gfp_mask);
 }
 
 /* [start, end) must belong to a single zone. */
index a15a466d0d1d14b21bd82de2bfd3df31654420db..c15b998e5a860f9d3c375ad31ce9d5f34fbb5ea0 100644 (file)
@@ -263,6 +263,24 @@ static int shmem_radix_tree_replace(struct address_space *mapping,
        return 0;
 }
 
+/*
+ * Sometimes, before we decide whether to proceed or to fail, we must check
+ * that an entry was not already brought back from swap by a racing thread.
+ *
+ * Checking page is not enough: by the time a SwapCache page is locked, it
+ * might be reused, and again be SwapCache, using the same swap as before.
+ */
+static bool shmem_confirm_swap(struct address_space *mapping,
+                              pgoff_t index, swp_entry_t swap)
+{
+       void *item;
+
+       rcu_read_lock();
+       item = radix_tree_lookup(&mapping->page_tree, index);
+       rcu_read_unlock();
+       return item == swp_to_radix_entry(swap);
+}
+
 /*
  * Like add_to_page_cache_locked, but error if expected item has gone.
  */
@@ -270,40 +288,31 @@ static int shmem_add_to_page_cache(struct page *page,
                                   struct address_space *mapping,
                                   pgoff_t index, gfp_t gfp, void *expected)
 {
-       int error = 0;
+       int error;
 
        VM_BUG_ON(!PageLocked(page));
        VM_BUG_ON(!PageSwapBacked(page));
 
+       page_cache_get(page);
+       page->mapping = mapping;
+       page->index = index;
+
+       spin_lock_irq(&mapping->tree_lock);
        if (!expected)
-               error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
+               error = radix_tree_insert(&mapping->page_tree, index, page);
+       else
+               error = shmem_radix_tree_replace(mapping, index, expected,
+                                                                page);
        if (!error) {
-               page_cache_get(page);
-               page->mapping = mapping;
-               page->index = index;
-
-               spin_lock_irq(&mapping->tree_lock);
-               if (!expected)
-                       error = radix_tree_insert(&mapping->page_tree,
-                                                       index, page);
-               else
-                       error = shmem_radix_tree_replace(mapping, index,
-                                                       expected, page);
-               if (!error) {
-                       mapping->nrpages++;
-                       __inc_zone_page_state(page, NR_FILE_PAGES);
-                       __inc_zone_page_state(page, NR_SHMEM);
-                       spin_unlock_irq(&mapping->tree_lock);
-               } else {
-                       page->mapping = NULL;
-                       spin_unlock_irq(&mapping->tree_lock);
-                       page_cache_release(page);
-               }
-               if (!expected)
-                       radix_tree_preload_end();
+               mapping->nrpages++;
+               __inc_zone_page_state(page, NR_FILE_PAGES);
+               __inc_zone_page_state(page, NR_SHMEM);
+               spin_unlock_irq(&mapping->tree_lock);
+       } else {
+               page->mapping = NULL;
+               spin_unlock_irq(&mapping->tree_lock);
+               page_cache_release(page);
        }
-       if (error)
-               mem_cgroup_uncharge_cache_page(page);
        return error;
 }
 
@@ -1124,9 +1133,9 @@ repeat:
                /* We have to do this with page locked to prevent races */
                lock_page(page);
                if (!PageSwapCache(page) || page_private(page) != swap.val ||
-                   page->mapping) {
+                   !shmem_confirm_swap(mapping, index, swap)) {
                        error = -EEXIST;        /* try again */
-                       goto failed;
+                       goto unlock;
                }
                if (!PageUptodate(page)) {
                        error = -EIO;
@@ -1142,9 +1151,12 @@ repeat:
 
                error = mem_cgroup_cache_charge(page, current->mm,
                                                gfp & GFP_RECLAIM_MASK);
-               if (!error)
+               if (!error) {
                        error = shmem_add_to_page_cache(page, mapping, index,
                                                gfp, swp_to_radix_entry(swap));
+                       /* We already confirmed swap, and make no allocation */
+                       VM_BUG_ON(error);
+               }
                if (error)
                        goto failed;
 
@@ -1181,11 +1193,18 @@ repeat:
                __set_page_locked(page);
                error = mem_cgroup_cache_charge(page, current->mm,
                                                gfp & GFP_RECLAIM_MASK);
-               if (!error)
-                       error = shmem_add_to_page_cache(page, mapping, index,
-                                               gfp, NULL);
                if (error)
                        goto decused;
+               error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
+               if (!error) {
+                       error = shmem_add_to_page_cache(page, mapping, index,
+                                                       gfp, NULL);
+                       radix_tree_preload_end();
+               }
+               if (error) {
+                       mem_cgroup_uncharge_cache_page(page);
+                       goto decused;
+               }
                lru_cache_add_anon(page);
 
                spin_lock(&info->lock);
@@ -1245,14 +1264,10 @@ decused:
 unacct:
        shmem_unacct_blocks(info->flags, 1);
 failed:
-       if (swap.val && error != -EINVAL) {
-               struct page *test = find_get_page(mapping, index);
-               if (test && !radix_tree_exceptional_entry(test))
-                       page_cache_release(test);
-               /* Have another try if the entry has changed */
-               if (test != swp_to_radix_entry(swap))
-                       error = -EEXIST;
-       }
+       if (swap.val && error != -EINVAL &&
+           !shmem_confirm_swap(mapping, index, swap))
+               error = -EEXIST;
+unlock:
        if (page) {
                unlock_page(page);
                page_cache_release(page);
@@ -1264,7 +1279,7 @@ failed:
                spin_unlock(&info->lock);
                goto repeat;
        }
-       if (error == -EEXIST)
+       if (error == -EEXIST)   /* from above or from radix_tree_insert */
                goto repeat;
        return error;
 }
@@ -1594,6 +1609,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
        struct splice_pipe_desc spd = {
                .pages = pages,
                .partial = partial,
+               .nr_pages_max = PIPE_DEF_BUFFERS,
                .flags = flags,
                .ops = &page_cache_pipe_buf_ops,
                .spd_release = spd_release_page,
@@ -1682,7 +1698,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
        if (spd.nr_pages)
                error = splice_to_pipe(pipe, &spd);
 
-       splice_shrink_spd(pipe, &spd);
+       splice_shrink_spd(&spd);
 
        if (error > 0) {
                *ppos += error;
@@ -1691,98 +1707,6 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
        return error;
 }
 
-/*
- * llseek SEEK_DATA or SEEK_HOLE through the radix_tree.
- */
-static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
-                                   pgoff_t index, pgoff_t end, int origin)
-{
-       struct page *page;
-       struct pagevec pvec;
-       pgoff_t indices[PAGEVEC_SIZE];
-       bool done = false;
-       int i;
-
-       pagevec_init(&pvec, 0);
-       pvec.nr = 1;            /* start small: we may be there already */
-       while (!done) {
-               pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
-                                       pvec.nr, pvec.pages, indices);
-               if (!pvec.nr) {
-                       if (origin == SEEK_DATA)
-                               index = end;
-                       break;
-               }
-               for (i = 0; i < pvec.nr; i++, index++) {
-                       if (index < indices[i]) {
-                               if (origin == SEEK_HOLE) {
-                                       done = true;
-                                       break;
-                               }
-                               index = indices[i];
-                       }
-                       page = pvec.pages[i];
-                       if (page && !radix_tree_exceptional_entry(page)) {
-                               if (!PageUptodate(page))
-                                       page = NULL;
-                       }
-                       if (index >= end ||
-                           (page && origin == SEEK_DATA) ||
-                           (!page && origin == SEEK_HOLE)) {
-                               done = true;
-                               break;
-                       }
-               }
-               shmem_deswap_pagevec(&pvec);
-               pagevec_release(&pvec);
-               pvec.nr = PAGEVEC_SIZE;
-               cond_resched();
-       }
-       return index;
-}
-
-static loff_t shmem_file_llseek(struct file *file, loff_t offset, int origin)
-{
-       struct address_space *mapping;
-       struct inode *inode;
-       pgoff_t start, end;
-       loff_t new_offset;
-
-       if (origin != SEEK_DATA && origin != SEEK_HOLE)
-               return generic_file_llseek_size(file, offset, origin,
-                                                       MAX_LFS_FILESIZE);
-       mapping = file->f_mapping;
-       inode = mapping->host;
-       mutex_lock(&inode->i_mutex);
-       /* We're holding i_mutex so we can access i_size directly */
-
-       if (offset < 0)
-               offset = -EINVAL;
-       else if (offset >= inode->i_size)
-               offset = -ENXIO;
-       else {
-               start = offset >> PAGE_CACHE_SHIFT;
-               end = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-               new_offset = shmem_seek_hole_data(mapping, start, end, origin);
-               new_offset <<= PAGE_CACHE_SHIFT;
-               if (new_offset > offset) {
-                       if (new_offset < inode->i_size)
-                               offset = new_offset;
-                       else if (origin == SEEK_DATA)
-                               offset = -ENXIO;
-                       else
-                               offset = inode->i_size;
-               }
-       }
-
-       if (offset >= 0 && offset != file->f_pos) {
-               file->f_pos = offset;
-               file->f_version = 0;
-       }
-       mutex_unlock(&inode->i_mutex);
-       return offset;
-}
-
 static long shmem_fallocate(struct file *file, int mode, loff_t offset,
                                                         loff_t len)
 {
@@ -1953,7 +1877,7 @@ static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 }
 
 static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               struct nameidata *nd)
+               bool excl)
 {
        return shmem_mknod(dir, dentry, mode | S_IFREG, 0);
 }
@@ -2786,7 +2710,7 @@ static const struct address_space_operations shmem_aops = {
 static const struct file_operations shmem_file_operations = {
        .mmap           = shmem_mmap,
 #ifdef CONFIG_TMPFS
-       .llseek         = shmem_file_llseek,
+       .llseek         = generic_file_llseek,
        .read           = do_sync_read,
        .write          = do_sync_write,
        .aio_read       = shmem_file_aio_read,
index 6a4bf9160e855ae1e2d61fefb4922918f710bb24..c7bb952400c83c9114a401f647955cb18dd2ea44 100644 (file)
@@ -275,8 +275,9 @@ static unsigned long * __init
 sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
                                         unsigned long size)
 {
-       pg_data_t *host_pgdat;
-       unsigned long goal;
+       unsigned long goal, limit;
+       unsigned long *p;
+       int nid;
        /*
         * A page may contain usemaps for other sections preventing the
         * page being freed and making a section unremovable while
@@ -287,10 +288,17 @@ sparse_early_usemaps_alloc_pgdat_section(struct pglist_data *pgdat,
         * from the same section as the pgdat where possible to avoid
         * this problem.
         */
-       goal = __pa(pgdat) & PAGE_SECTION_MASK;
-       host_pgdat = NODE_DATA(early_pfn_to_nid(goal >> PAGE_SHIFT));
-       return __alloc_bootmem_node_nopanic(host_pgdat, size,
-                                           SMP_CACHE_BYTES, goal);
+       goal = __pa(pgdat) & (PAGE_SECTION_MASK << PAGE_SHIFT);
+       limit = goal + (1UL << PA_SECTION_SHIFT);
+       nid = early_pfn_to_nid(goal >> PAGE_SHIFT);
+again:
+       p = ___alloc_bootmem_node_nopanic(NODE_DATA(nid), size,
+                                         SMP_CACHE_BYTES, goal, limit);
+       if (!p && limit) {
+               limit = 0;
+               goto again;
+       }
+       return p;
 }
 
 static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
index eeb3bc9d1d361b6f20821073485f1b8e7c4931d3..66e431060c05616ace60c4d512e4b96e785723ae 100644 (file)
@@ -2688,7 +2688,10 @@ static void kswapd_try_to_sleep(pg_data_t *pgdat, int order, int classzone_idx)
                 * them before going back to sleep.
                 */
                set_pgdat_percpu_threshold(pgdat, calculate_normal_threshold);
-               schedule();
+
+               if (!kthread_should_stop())
+                       schedule();
+
                set_pgdat_percpu_threshold(pgdat, calculate_pressure_threshold);
        } else {
                if (remaining)
@@ -2955,14 +2958,17 @@ int kswapd_run(int nid)
 }
 
 /*
- * Called by memory hotplug when all memory in a node is offlined.
+ * Called by memory hotplug when all memory in a node is offlined.  Caller must
+ * hold lock_memory_hotplug().
  */
 void kswapd_stop(int nid)
 {
        struct task_struct *kswapd = NODE_DATA(nid)->kswapd;
 
-       if (kswapd)
+       if (kswapd) {
                kthread_stop(kswapd);
+               NODE_DATA(nid)->kswapd = NULL;
+       }
 }
 
 static int __init kswapd_init(void)
index 6089f0cf23b480e4686916823cecafd681a64f42..9096bcb081326c92bb64b6dedb11033073998ca5 100644 (file)
@@ -403,6 +403,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                break;
 
        case NETDEV_DOWN:
+               if (dev->features & NETIF_F_HW_VLAN_FILTER)
+                       vlan_vid_del(dev, 0);
+
                /* Put all VLANs for this dev in the down state too.  */
                for (i = 0; i < VLAN_N_VID; i++) {
                        vlandev = vlan_group_get_device(grp, i);
index 051f7abae66d987177536637c235865258cabbec..779095ded689918de025f48c47db880aa9b5d724 100644 (file)
@@ -842,6 +842,7 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol,
                case AX25_P_NETROM:
                        if (ax25_protocol_is_registered(AX25_P_NETROM))
                                return -ESOCKTNOSUPPORT;
+                       break;
 #endif
 #ifdef CONFIG_ROSE_MODULE
                case AX25_P_ROSE:
index 8bf97515a77d6f3ccfaae8ab3d89e1eaed46013a..c5863f499133b466787b8b5044882c4ddded194a 100644 (file)
@@ -1351,6 +1351,7 @@ void bla_free(struct bat_priv *bat_priv)
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the frame to be checked
  * @vid: the VLAN ID of the frame
+ * @is_bcast: the packet came in a broadcast packet type.
  *
  * bla_rx avoidance checks if:
  *  * we have to race for a claim
@@ -1361,7 +1362,8 @@ void bla_free(struct bat_priv *bat_priv)
  * process the skb.
  *
  */
-int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
+int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid,
+          bool is_bcast)
 {
        struct ethhdr *ethhdr;
        struct claim search_claim, *claim = NULL;
@@ -1380,7 +1382,7 @@ int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
 
        if (unlikely(atomic_read(&bat_priv->bla_num_requests)))
                /* don't allow broadcasts while requests are in flight */
-               if (is_multicast_ether_addr(ethhdr->h_dest))
+               if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast)
                        goto handled;
 
        memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN);
@@ -1406,8 +1408,13 @@ int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid)
        }
 
        /* if it is a broadcast ... */
-       if (is_multicast_ether_addr(ethhdr->h_dest)) {
-               /* ... drop it. the responsible gateway is in charge. */
+       if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) {
+               /* ... drop it. the responsible gateway is in charge.
+                *
+                * We need to check is_bcast because with the gateway
+                * feature, broadcasts (like DHCP requests) may be sent
+                * using a unicast packet type.
+                */
                goto handled;
        } else {
                /* seems the client considers us as its best gateway.
index e39f93acc28f749793200be5b020df41fd5554e6..dc5227b398d44c7b57eda34adc4b53b9a1281f9a 100644 (file)
@@ -23,7 +23,8 @@
 #define _NET_BATMAN_ADV_BLA_H_
 
 #ifdef CONFIG_BATMAN_ADV_BLA
-int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
+int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid,
+          bool is_bcast);
 int bla_tx(struct bat_priv *bat_priv, struct sk_buff *skb, short vid);
 int bla_is_backbone_gw(struct sk_buff *skb,
                       struct orig_node *orig_node, int hdr_size);
@@ -41,7 +42,7 @@ void bla_free(struct bat_priv *bat_priv);
 #else /* ifdef CONFIG_BATMAN_ADV_BLA */
 
 static inline int bla_rx(struct bat_priv *bat_priv, struct sk_buff *skb,
-                        short vid)
+                        short vid, bool is_bcast)
 {
        return 0;
 }
index 6e2530b020437e7243ff2a71d6098a11d7d5df52..a0ec0e4ada4c0acf9392136cff17198b766acd1f 100644 (file)
@@ -256,7 +256,11 @@ void interface_rx(struct net_device *soft_iface,
        struct bat_priv *bat_priv = netdev_priv(soft_iface);
        struct ethhdr *ethhdr;
        struct vlan_ethhdr *vhdr;
+       struct batman_header *batadv_header = (struct batman_header *)skb->data;
        short vid __maybe_unused = -1;
+       bool is_bcast;
+
+       is_bcast = (batadv_header->packet_type == BAT_BCAST);
 
        /* check if enough space is available for pulling, and pull */
        if (!pskb_may_pull(skb, hdr_size))
@@ -302,7 +306,7 @@ void interface_rx(struct net_device *soft_iface,
        /* Let the bridge loop avoidance check the packet. If will
         * not handle it, we can safely push it up.
         */
-       if (bla_rx(bat_priv, skb, vid))
+       if (bla_rx(bat_priv, skb, vid, is_bcast))
                goto out;
 
        netif_rx(skb);
index 554b3128960776af52c2cd9869e14fdad224566c..8c83c175b03a9f2379c253bd1c9e160b72457320 100644 (file)
@@ -561,9 +561,9 @@ static int __init caif_device_init(void)
 
 static void __exit caif_device_exit(void)
 {
-       unregister_pernet_subsys(&caif_net_ops);
        unregister_netdevice_notifier(&caif_device_notifier);
        dev_remove_pack(&caif_packet_type);
+       unregister_pernet_subsys(&caif_net_ops);
 }
 
 module_init(caif_device_init);
index b332c3d76059ea5c1fe1de82d17fac4884b714a2..10255e81be79d84c5428504c2a79be3180626f79 100644 (file)
@@ -1423,7 +1423,7 @@ static int process_connect(struct ceph_connection *con)
                 * dropped messages.
                 */
                dout("process_connect got RESET peer seq %u\n",
-                    le32_to_cpu(con->in_connect.connect_seq));
+                    le32_to_cpu(con->in_reply.connect_seq));
                pr_err("%s%lld %s connection reset\n",
                       ENTITY_NAME(con->peer_name),
                       ceph_pr_addr(&con->peer_addr.in_addr));
@@ -1450,10 +1450,10 @@ static int process_connect(struct ceph_connection *con)
                 * If we sent a smaller connect_seq than the peer has, try
                 * again with a larger value.
                 */
-               dout("process_connect got RETRY my seq = %u, peer_seq = %u\n",
+               dout("process_connect got RETRY_SESSION my seq %u, peer %u\n",
                     le32_to_cpu(con->out_connect.connect_seq),
-                    le32_to_cpu(con->in_connect.connect_seq));
-               con->connect_seq = le32_to_cpu(con->in_connect.connect_seq);
+                    le32_to_cpu(con->in_reply.connect_seq));
+               con->connect_seq = le32_to_cpu(con->in_reply.connect_seq);
                ceph_con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
@@ -1468,9 +1468,9 @@ static int process_connect(struct ceph_connection *con)
                 */
                dout("process_connect got RETRY_GLOBAL my %u peer_gseq %u\n",
                     con->peer_global_seq,
-                    le32_to_cpu(con->in_connect.global_seq));
+                    le32_to_cpu(con->in_reply.global_seq));
                get_global_seq(con->msgr,
-                              le32_to_cpu(con->in_connect.global_seq));
+                              le32_to_cpu(con->in_reply.global_seq));
                ceph_con_out_kvec_reset(con);
                ret = prepare_write_connect(con);
                if (ret < 0)
index 6df214041a5e5bfe85b948b41ce56e15af514860..1cb0d8a6aa6c5cd3d23741cd5b941a23805b08bd 100644 (file)
@@ -1136,8 +1136,8 @@ void dev_load(struct net *net, const char *name)
                no_module = request_module("netdev-%s", name);
        if (no_module && capable(CAP_SYS_MODULE)) {
                if (!request_module("%s", name))
-                       pr_err("Loading kernel module for a network device with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev-%s instead.\n",
-                              name);
+                       pr_warn("Loading kernel module for a network device with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev-%s instead.\n",
+                               name);
        }
 }
 EXPORT_SYMBOL(dev_load);
@@ -2444,8 +2444,12 @@ static void skb_update_prio(struct sk_buff *skb)
 {
        struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap);
 
-       if ((!skb->priority) && (skb->sk) && map)
-               skb->priority = map->priomap[skb->sk->sk_cgrp_prioidx];
+       if (!skb->priority && skb->sk && map) {
+               unsigned int prioidx = skb->sk->sk_cgrp_prioidx;
+
+               if (prioidx < map->priomap_len)
+                       skb->priority = map->priomap[prioidx];
+       }
 }
 #else
 #define skb_update_prio(skb)
@@ -6279,7 +6283,8 @@ static struct hlist_head *netdev_create_hash(void)
 /* Initialize per network namespace state */
 static int __net_init netdev_init(struct net *net)
 {
-       INIT_LIST_HEAD(&net->dev_base_head);
+       if (net != &init_net)
+               INIT_LIST_HEAD(&net->dev_base_head);
 
        net->dev_name_head = netdev_create_hash();
        if (net->dev_name_head == NULL)
index dddbacb8f28ccba180cd20855476d5d7e351b1b8..42f1e1c7514f67ad56df06ffe53e6c94a094681a 100644 (file)
@@ -27,7 +27,9 @@ static DEFINE_MUTEX(net_mutex);
 LIST_HEAD(net_namespace_list);
 EXPORT_SYMBOL_GPL(net_namespace_list);
 
-struct net init_net;
+struct net init_net = {
+       .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head),
+};
 EXPORT_SYMBOL(init_net);
 
 #define INITIAL_NET_GEN_PTRS   13 /* +1 for len +2 for rcu_head */
index 5b8aa2fae48b84e3255ecdfe83535457bd170901..b2e9caa1ad1aa761ba98886a23ce3823bdc179ee 100644 (file)
@@ -49,8 +49,9 @@ static int get_prioidx(u32 *prio)
                return -ENOSPC;
        }
        set_bit(prioidx, prioidx_map);
+       if (atomic_read(&max_prioidx) < prioidx)
+               atomic_set(&max_prioidx, prioidx);
        spin_unlock_irqrestore(&prioidx_map_lock, flags);
-       atomic_set(&max_prioidx, prioidx);
        *prio = prioidx;
        return 0;
 }
@@ -64,7 +65,7 @@ static void put_prioidx(u32 idx)
        spin_unlock_irqrestore(&prioidx_map_lock, flags);
 }
 
-static void extend_netdev_table(struct net_device *dev, u32 new_len)
+static int extend_netdev_table(struct net_device *dev, u32 new_len)
 {
        size_t new_size = sizeof(struct netprio_map) +
                           ((sizeof(u32) * new_len));
@@ -76,7 +77,7 @@ static void extend_netdev_table(struct net_device *dev, u32 new_len)
 
        if (!new_priomap) {
                pr_warn("Unable to alloc new priomap!\n");
-               return;
+               return -ENOMEM;
        }
 
        for (i = 0;
@@ -89,46 +90,79 @@ static void extend_netdev_table(struct net_device *dev, u32 new_len)
        rcu_assign_pointer(dev->priomap, new_priomap);
        if (old_priomap)
                kfree_rcu(old_priomap, rcu);
+       return 0;
 }
 
-static void update_netdev_tables(void)
+static int write_update_netdev_table(struct net_device *dev)
 {
+       int ret = 0;
+       u32 max_len;
+       struct netprio_map *map;
+
+       rtnl_lock();
+       max_len = atomic_read(&max_prioidx) + 1;
+       map = rtnl_dereference(dev->priomap);
+       if (!map || map->priomap_len < max_len)
+               ret = extend_netdev_table(dev, max_len);
+       rtnl_unlock();
+
+       return ret;
+}
+
+static int update_netdev_tables(void)
+{
+       int ret = 0;
        struct net_device *dev;
-       u32 max_len = atomic_read(&max_prioidx) + 1;
+       u32 max_len;
        struct netprio_map *map;
 
        rtnl_lock();
+       max_len = atomic_read(&max_prioidx) + 1;
        for_each_netdev(&init_net, dev) {
                map = rtnl_dereference(dev->priomap);
-               if ((!map) ||
-                   (map->priomap_len < max_len))
-                       extend_netdev_table(dev, max_len);
+               /*
+                * don't allocate priomap if we didn't
+                * change net_prio.ifpriomap (map == NULL),
+                * this will speed up skb_update_prio.
+                */
+               if (map && map->priomap_len < max_len) {
+                       ret = extend_netdev_table(dev, max_len);
+                       if (ret < 0)
+                               break;
+               }
        }
        rtnl_unlock();
+       return ret;
 }
 
 static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp)
 {
        struct cgroup_netprio_state *cs;
-       int ret;
+       int ret = -EINVAL;
 
        cs = kzalloc(sizeof(*cs), GFP_KERNEL);
        if (!cs)
                return ERR_PTR(-ENOMEM);
 
-       if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx) {
-               kfree(cs);
-               return ERR_PTR(-EINVAL);
-       }
+       if (cgrp->parent && cgrp_netprio_state(cgrp->parent)->prioidx)
+               goto out;
 
        ret = get_prioidx(&cs->prioidx);
-       if (ret != 0) {
+       if (ret < 0) {
                pr_warn("No space in priority index array\n");
-               kfree(cs);
-               return ERR_PTR(ret);
+               goto out;
+       }
+
+       ret = update_netdev_tables();
+       if (ret < 0) {
+               put_prioidx(cs->prioidx);
+               goto out;
        }
 
        return &cs->css;
+out:
+       kfree(cs);
+       return ERR_PTR(ret);
 }
 
 static void cgrp_destroy(struct cgroup *cgrp)
@@ -141,7 +175,7 @@ static void cgrp_destroy(struct cgroup *cgrp)
        rtnl_lock();
        for_each_netdev(&init_net, dev) {
                map = rtnl_dereference(dev->priomap);
-               if (map)
+               if (map && cs->prioidx < map->priomap_len)
                        map->priomap[cs->prioidx] = 0;
        }
        rtnl_unlock();
@@ -165,7 +199,7 @@ static int read_priomap(struct cgroup *cont, struct cftype *cft,
        rcu_read_lock();
        for_each_netdev_rcu(&init_net, dev) {
                map = rcu_dereference(dev->priomap);
-               priority = map ? map->priomap[prioidx] : 0;
+               priority = (map && prioidx < map->priomap_len) ? map->priomap[prioidx] : 0;
                cb->fill(cb, dev->name, priority);
        }
        rcu_read_unlock();
@@ -220,13 +254,17 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
        if (!dev)
                goto out_free_devname;
 
-       update_netdev_tables();
-       ret = 0;
+       ret = write_update_netdev_table(dev);
+       if (ret < 0)
+               goto out_put_dev;
+
        rcu_read_lock();
        map = rcu_dereference(dev->priomap);
        if (map)
                map->priomap[prioidx] = priority;
        rcu_read_unlock();
+
+out_put_dev:
        dev_put(dev);
 
 out_free_devname:
index 611c5efd4cb0b71abeb9b3d965acbf490673e644..8f6ccfd68ef4fb6625652f0b34f7f3fdb4b4a91e 100644 (file)
@@ -109,25 +109,9 @@ void __scm_destroy(struct scm_cookie *scm)
 
        if (fpl) {
                scm->fp = NULL;
-               if (current->scm_work_list) {
-                       list_add_tail(&fpl->list, current->scm_work_list);
-               } else {
-                       LIST_HEAD(work_list);
-
-                       current->scm_work_list = &work_list;
-
-                       list_add(&fpl->list, &work_list);
-                       while (!list_empty(&work_list)) {
-                               fpl = list_first_entry(&work_list, struct scm_fp_list, list);
-
-                               list_del(&fpl->list);
-                               for (i=fpl->count-1; i>=0; i--)
-                                       fput(fpl->fp[i]);
-                               kfree(fpl);
-                       }
-
-                       current->scm_work_list = NULL;
-               }
+               for (i=fpl->count-1; i>=0; i--)
+                       fput(fpl->fp[i]);
+               kfree(fpl);
        }
 }
 EXPORT_SYMBOL(__scm_destroy);
index d78671e9d545be838f9ab5140c9ee07fb1309c26..d124306b81fdbf73171d0921e401321f44f63711 100644 (file)
@@ -353,7 +353,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
        unsigned int fragsz = SKB_DATA_ALIGN(length + NET_SKB_PAD) +
                              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 
-       if (fragsz <= PAGE_SIZE && !(gfp_mask & __GFP_WAIT)) {
+       if (fragsz <= PAGE_SIZE && !(gfp_mask & (__GFP_WAIT | GFP_DMA))) {
                void *data = netdev_alloc_frag(fragsz);
 
                if (likely(data)) {
@@ -1755,6 +1755,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
        struct splice_pipe_desc spd = {
                .pages = pages,
                .partial = partial,
+               .nr_pages_max = MAX_SKB_FRAGS,
                .flags = flags,
                .ops = &sock_pipe_buf_ops,
                .spd_release = sock_spd_release,
index 6fbb2ad7bb6df480a71612054003a6176fc12447..16705611589ab6abd1a2e67811d0e38d6d8b4d26 100644 (file)
@@ -230,6 +230,12 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
        mtu = dev->mtu;
        pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
 
+       if (size > mtu) {
+               pr_debug("size = %Zu, mtu = %u\n", size, mtu);
+               err = -EINVAL;
+               goto out_dev;
+       }
+
        hlen = LL_RESERVED_SPACE(dev);
        tlen = dev->needed_tailroom;
        skb = sock_alloc_send_skb(sk, hlen + tlen + size,
@@ -258,12 +264,6 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
        if (err < 0)
                goto out_skb;
 
-       if (size > mtu) {
-               pr_debug("size = %Zu, mtu = %u\n", size, mtu);
-               err = -EINVAL;
-               goto out_skb;
-       }
-
        skb->dev = dev;
        skb->sk  = sk;
        skb->protocol = htons(ETH_P_IEEE802154);
index c48adc565e9239a45c600d791c8f97059e22696f..667c1d4ca9847c627127dc633e19c7c94f354188 100644 (file)
@@ -1725,8 +1725,10 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
                case CIPSO_V4_TAG_LOCAL:
                        /* This is a non-standard tag that we only allow for
                         * local connections, so if the incoming interface is
-                        * not the loopback device drop the packet. */
-                       if (!(skb->dev->flags & IFF_LOOPBACK)) {
+                        * not the loopback device drop the packet. Further,
+                        * there is no legitimate reason for setting this from
+                        * userspace so reject it if skb is NULL. */
+                       if (skb == NULL || !(skb->dev->flags & IFF_LOOPBACK)) {
                                err_offset = opt_iter;
                                goto validate_return_locked;
                        }
index 66e4fcdd1c6b4a6a07a7d26f3a66bc7e43183807..0db5d34a06b69c8c72798a8a7d4e6c4f642f7560 100644 (file)
@@ -1342,7 +1342,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        u32 changed = 0;
-       u8 bssid[ETH_ALEN];
 
        ASSERT_MGD_MTX(ifmgd);
 
@@ -1354,10 +1353,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_stop_poll(sdata);
 
-       memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
-
        ifmgd->associated = NULL;
-       memset(ifmgd->bssid, 0, ETH_ALEN);
 
        /*
         * we need to commit the associated = NULL change because the
@@ -1377,7 +1373,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        netif_carrier_off(sdata->dev);
 
        mutex_lock(&local->sta_mtx);
-       sta = sta_info_get(sdata, bssid);
+       sta = sta_info_get(sdata, ifmgd->bssid);
        if (sta) {
                set_sta_flag(sta, WLAN_STA_BLOCK_BA);
                ieee80211_sta_tear_down_BA_sessions(sta, tx);
@@ -1386,13 +1382,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        /* deauthenticate/disassociate now */
        if (tx || frame_buf)
-               ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason,
-                                              tx, frame_buf);
+               ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
+                                              reason, tx, frame_buf);
 
        /* flush out frame */
        if (tx)
                drv_flush(local, false);
 
+       /* clear bssid only after building the needed mgmt frames */
+       memset(ifmgd->bssid, 0, ETH_ALEN);
+
        /* remove AP and TDLS peers */
        sta_info_flush(local, sdata);
 
@@ -2175,15 +2174,13 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                       sdata->name, mgmt->sa, status_code);
                ieee80211_destroy_assoc_data(sdata, false);
        } else {
-               printk(KERN_DEBUG "%s: associated\n", sdata->name);
-
                if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) {
                        /* oops -- internal error -- send timeout for now */
-                       ieee80211_destroy_assoc_data(sdata, true);
-                       sta_info_destroy_addr(sdata, mgmt->bssid);
+                       ieee80211_destroy_assoc_data(sdata, false);
                        cfg80211_put_bss(*bss);
                        return RX_MGMT_CFG80211_ASSOC_TIMEOUT;
                }
+               printk(KERN_DEBUG "%s: associated\n", sdata->name);
 
                /*
                 * destroy assoc_data afterwards, as otherwise an idle
index 2d1acc6c54455de4d397dc64cc471d8890e95bc7..f9e51ef8dfa2432ec44168feebc82579f3ac0be6 100644 (file)
@@ -809,7 +809,7 @@ minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
                        max_rates = sband->n_bitrates;
        }
 
-       msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp);
+       msp = kzalloc(sizeof(*msp), gfp);
        if (!msp)
                return NULL;
 
index 7bcecf73aafbf9dadb87a2c8a114e3eb92490131..965e6ec0adb6c12393ced183a44463a63e09a9ff 100644 (file)
@@ -2455,7 +2455,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
         * frames that we didn't handle, including returning unknown
         * ones. For all other modes we will return them to the sender,
         * setting the 0x80 bit in the action category, as required by
-        * 802.11-2007 7.3.1.11.
+        * 802.11-2012 9.24.4.
         * Newer versions of hostapd shall also use the management frame
         * registration mechanisms, but older ones still use cooked
         * monitor interfaces so push all frames there.
@@ -2465,6 +2465,9 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
             sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
                return RX_DROP_MONITOR;
 
+       if (is_multicast_ether_addr(mgmt->da))
+               return RX_DROP_MONITOR;
+
        /* do not return rejected action frames */
        if (mgmt->u.action.category & 0x80)
                return RX_DROP_UNUSABLE;
index 819c342f5b3012b6a4e37f60414fb835fc0041d8..9730882697aaedbab0beee66f0f12a654b97b63a 100644 (file)
@@ -639,6 +639,14 @@ find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set)
        return 0;
 }
 
+static int
+ip_set_none(struct sock *ctnl, struct sk_buff *skb,
+           const struct nlmsghdr *nlh,
+           const struct nlattr * const attr[])
+{
+       return -EOPNOTSUPP;
+}
+
 static int
 ip_set_create(struct sock *ctnl, struct sk_buff *skb,
              const struct nlmsghdr *nlh,
@@ -1539,6 +1547,10 @@ nlmsg_failure:
 }
 
 static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
+       [IPSET_CMD_NONE]        = {
+               .call           = ip_set_none,
+               .attr_count     = IPSET_ATTR_CMD_MAX,
+       },
        [IPSET_CMD_CREATE]      = {
                .call           = ip_set_create,
                .attr_count     = IPSET_ATTR_CMD_MAX,
index ee863943c8267286e4b16e52400dd40bf51b4f26..d5d3607ae7bcf5e9704bd189217115cf048aee4b 100644 (file)
@@ -38,30 +38,6 @@ struct iface_node {
 
 #define iface_data(n)  (rb_entry(n, struct iface_node, node)->iface)
 
-static inline long
-ifname_compare(const char *_a, const char *_b)
-{
-       const long *a = (const long *)_a;
-       const long *b = (const long *)_b;
-
-       BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
-       if (a[0] != b[0])
-               return a[0] - b[0];
-       if (IFNAMSIZ > sizeof(long)) {
-               if (a[1] != b[1])
-                       return a[1] - b[1];
-       }
-       if (IFNAMSIZ > 2 * sizeof(long)) {
-               if (a[2] != b[2])
-                       return a[2] - b[2];
-       }
-       if (IFNAMSIZ > 3 * sizeof(long)) {
-               if (a[3] != b[3])
-                       return a[3] - b[3];
-       }
-       return 0;
-}
-
 static void
 rbtree_destroy(struct rb_root *root)
 {
@@ -99,7 +75,7 @@ iface_test(struct rb_root *root, const char **iface)
 
        while (n) {
                const char *d = iface_data(n);
-               long res = ifname_compare(*iface, d);
+               int res = strcmp(*iface, d);
 
                if (res < 0)
                        n = n->rb_left;
@@ -121,7 +97,7 @@ iface_add(struct rb_root *root, const char **iface)
 
        while (*n) {
                char *ifname = iface_data(*n);
-               long res = ifname_compare(*iface, ifname);
+               int res = strcmp(*iface, ifname);
 
                p = *n;
                if (res < 0)
@@ -366,7 +342,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
        struct hash_netiface4_elem data = { .cidr = HOST_MASK };
        u32 ip = 0, ip_to, last;
        u32 timeout = h->timeout;
-       char iface[IFNAMSIZ] = {};
+       char iface[IFNAMSIZ];
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -663,7 +639,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netiface6_elem data = { .cidr = HOST_MASK };
        u32 timeout = h->timeout;
-       char iface[IFNAMSIZ] = {};
+       char iface[IFNAMSIZ];
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
index dd811b8dd97c66a9da387a4e37073c47e8dc4407..84444dda194b61806efaeadde4c2458f502d8283 100644 (file)
@@ -76,19 +76,19 @@ static void __ip_vs_del_service(struct ip_vs_service *svc);
 
 #ifdef CONFIG_IP_VS_IPV6
 /* Taken from rt6_fill_node() in net/ipv6/route.c, is there a better way? */
-static int __ip_vs_addr_is_local_v6(struct net *net,
-                                   const struct in6_addr *addr)
+static bool __ip_vs_addr_is_local_v6(struct net *net,
+                                    const struct in6_addr *addr)
 {
-       struct rt6_info *rt;
        struct flowi6 fl6 = {
                .daddr = *addr,
        };
+       struct dst_entry *dst = ip6_route_output(net, NULL, &fl6);
+       bool is_local;
 
-       rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
-       if (rt && rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK))
-               return 1;
+       is_local = !dst->error && dst->dev && (dst->dev->flags & IFF_LOOPBACK);
 
-       return 0;
+       dst_release(dst);
+       return is_local;
 }
 #endif
 
@@ -1521,11 +1521,12 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
 {
        struct net_device *dev = ptr;
        struct net *net = dev_net(dev);
+       struct netns_ipvs *ipvs = net_ipvs(net);
        struct ip_vs_service *svc;
        struct ip_vs_dest *dest;
        unsigned int idx;
 
-       if (event != NETDEV_UNREGISTER)
+       if (event != NETDEV_UNREGISTER || !ipvs)
                return NOTIFY_DONE;
        IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name);
        EnterFunction(2);
@@ -1551,7 +1552,7 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
                }
        }
 
-       list_for_each_entry(dest, &net_ipvs(net)->dest_trash, n_list) {
+       list_for_each_entry(dest, &ipvs->dest_trash, n_list) {
                __ip_vs_dev_reset(dest, dev);
        }
        mutex_unlock(&__ip_vs_mutex);
index 3e797d1fcb94272ad96b9798e91a6e6467031379..791d56bbd74a7613e4b1d87ba74bcf2a8a135e46 100644 (file)
@@ -169,8 +169,10 @@ replay:
 
                err = nla_parse(cda, ss->cb[cb_id].attr_count,
                                attr, attrlen, ss->cb[cb_id].policy);
-               if (err < 0)
+               if (err < 0) {
+                       rcu_read_unlock();
                        return err;
+               }
 
                if (nc->call_rcu) {
                        err = nc->call_rcu(net->nfnl, skb, nlh,
index 035960ec5cb9c8f51b51e48d6909ebb112047f93..c6f7db720d84f4650e975a952054c04d15868fc3 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_set.h>
+#include <linux/netfilter/ipset/ip_set_timeout.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -310,7 +311,8 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
                info->del_set.flags, 0, UINT_MAX);
 
        /* Normalize to fit into jiffies */
-       if (add_opt.timeout > UINT_MAX/MSEC_PER_SEC)
+       if (add_opt.timeout != IPSET_NO_TIMEOUT &&
+           add_opt.timeout > UINT_MAX/MSEC_PER_SEC)
                add_opt.timeout = UINT_MAX/MSEC_PER_SEC;
        if (info->add_set.index != IPSET_INVALID_ID)
                ip_set_add(info->add_set.index, skb, par, &add_opt);
index 17a707db40eb9865000cd073d3661fef1d1ced13..e06d458fc7197ff73e1f1f6f155c154c330cfa67 100644 (file)
@@ -292,7 +292,7 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr,
 
        pr_debug("%p\n", sk);
 
-       if (llcp_sock == NULL)
+       if (llcp_sock == NULL || llcp_sock->dev == NULL)
                return -EBADFD;
 
        addr->sa_family = AF_NFC;
index cb2646179e5f8b8d1836499579d1ccfd109fad60..2ab196a9f228ac873238c2a060685bacea62b87a 100644 (file)
@@ -106,7 +106,7 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
        nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
        data += 2;
 
-       nfca_poll->nfcid1_len = *data++;
+       nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE);
 
        pr_debug("sens_res 0x%x, nfcid1_len %d\n",
                 nfca_poll->sens_res, nfca_poll->nfcid1_len);
@@ -130,7 +130,7 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
                        struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
                                                     __u8 *data)
 {
-       nfcb_poll->sensb_res_len = *data++;
+       nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE);
 
        pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len);
 
@@ -145,7 +145,7 @@ static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
                                                     __u8 *data)
 {
        nfcf_poll->bit_rate = *data++;
-       nfcf_poll->sensf_res_len = *data++;
+       nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE);
 
        pr_debug("bit_rate %d, sensf_res_len %d\n",
                 nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
@@ -331,7 +331,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
        switch (ntf->activation_rf_tech_and_mode) {
        case NCI_NFC_A_PASSIVE_POLL_MODE:
                nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
-               nfca_poll->rats_res_len = *data++;
+               nfca_poll->rats_res_len = min_t(__u8, *data++, 20);
                pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
                if (nfca_poll->rats_res_len > 0) {
                        memcpy(nfca_poll->rats_res,
@@ -341,7 +341,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
 
        case NCI_NFC_B_PASSIVE_POLL_MODE:
                nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep;
-               nfcb_poll->attrib_res_len = *data++;
+               nfcb_poll->attrib_res_len = min_t(__u8, *data++, 50);
                pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len);
                if (nfcb_poll->attrib_res_len > 0) {
                        memcpy(nfcb_poll->attrib_res,
index ec1134c9e07fcd34fc5d6116e1a4aef9dedf6f23..8b8a6a2b2badaf61e9c71a174809ca989438668f 100644 (file)
@@ -54,7 +54,10 @@ static int rawsock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       pr_debug("sock=%p\n", sock);
+       pr_debug("sock=%p sk=%p\n", sock, sk);
+
+       if (!sk)
+               return 0;
 
        sock_orphan(sk);
        sock_put(sk);
index 2754f098d43633f80c0a39b7c34a35296d5523ea..bebaa43484bcdbf72bbaaa764559051aeb8efb99 100644 (file)
@@ -229,7 +229,7 @@ found_UDP_peer:
        return peer;
 
 new_UDP_peer:
-       _net("Rx UDP DGRAM from NEW peer %d", peer->debug_id);
+       _net("Rx UDP DGRAM from NEW peer");
        read_unlock_bh(&rxrpc_peer_lock);
        _leave(" = -EBUSY [new]");
        return ERR_PTR(-EBUSY);
index a2a95aabf9c22bd3b0b0bbbe558feb1c1f65430a..c412ad0d0308ed8aedee1c5ce69bce323a32b823 100644 (file)
@@ -331,29 +331,22 @@ static psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sche
        return PSCHED_NS2TICKS(ticks);
 }
 
-static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
+static void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
 {
        struct sk_buff_head *list = &sch->q;
        psched_time_t tnext = netem_skb_cb(nskb)->time_to_send;
-       struct sk_buff *skb;
-
-       if (likely(skb_queue_len(list) < sch->limit)) {
-               skb = skb_peek_tail(list);
-               /* Optimize for add at tail */
-               if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send))
-                       return qdisc_enqueue_tail(nskb, sch);
+       struct sk_buff *skb = skb_peek_tail(list);
 
-               skb_queue_reverse_walk(list, skb) {
-                       if (tnext >= netem_skb_cb(skb)->time_to_send)
-                               break;
-               }
+       /* Optimize for add at tail */
+       if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send))
+               return __skb_queue_tail(list, nskb);
 
-               __skb_queue_after(list, skb, nskb);
-               sch->qstats.backlog += qdisc_pkt_len(nskb);
-               return NET_XMIT_SUCCESS;
+       skb_queue_reverse_walk(list, skb) {
+               if (tnext >= netem_skb_cb(skb)->time_to_send)
+                       break;
        }
 
-       return qdisc_reshape_fail(nskb, sch);
+       __skb_queue_after(list, skb, nskb);
 }
 
 /*
@@ -368,7 +361,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        /* We don't fill cb now as skb_unshare() may invalidate it */
        struct netem_skb_cb *cb;
        struct sk_buff *skb2;
-       int ret;
        int count = 1;
 
        /* Random duplication */
@@ -419,6 +411,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8);
        }
 
+       if (unlikely(skb_queue_len(&sch->q) >= sch->limit))
+               return qdisc_reshape_fail(skb, sch);
+
+       sch->qstats.backlog += qdisc_pkt_len(skb);
+
        cb = netem_skb_cb(skb);
        if (q->gap == 0 ||              /* not doing reordering */
            q->counter < q->gap - 1 ||  /* inside last reordering gap */
@@ -450,7 +447,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
                cb->time_to_send = now + delay;
                ++q->counter;
-               ret = tfifo_enqueue(skb, sch);
+               tfifo_enqueue(skb, sch);
        } else {
                /*
                 * Do re-ordering by putting one out of N packets at the front
@@ -460,16 +457,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                q->counter = 0;
 
                __skb_queue_head(&sch->q, skb);
-               sch->qstats.backlog += qdisc_pkt_len(skb);
                sch->qstats.requeues++;
-               ret = NET_XMIT_SUCCESS;
-       }
-
-       if (ret != NET_XMIT_SUCCESS) {
-               if (net_xmit_drop_count(ret)) {
-                       sch->qstats.drops++;
-                       return ret;
-               }
        }
 
        return NET_XMIT_SUCCESS;
index 74305c883bd3ee842c535bbc27f003d389207346..30ea4674cabd2a735c47af22239ab006b1c2e826 100644 (file)
@@ -570,6 +570,8 @@ static int sfb_dump(struct Qdisc *sch, struct sk_buff *skb)
 
        sch->qstats.backlog = q->qdisc->qstats.backlog;
        opts = nla_nest_start(skb, TCA_OPTIONS);
+       if (opts == NULL)
+               goto nla_put_failure;
        if (nla_put(skb, TCA_SFB_PARMS, sizeof(opt), &opt))
                goto nla_put_failure;
        return nla_nest_end(skb, opts);
index 5bc9ab161b373eadf51843ebaa77c527716a2122..b16517ee1aaf7cfad94978ed1181df6432da6f07 100644 (file)
@@ -271,6 +271,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
         */
        asoc->peer.sack_needed = 1;
        asoc->peer.sack_cnt = 0;
+       asoc->peer.sack_generation = 1;
 
        /* Assume that the peer will tell us if he recognizes ASCONF
         * as part of INIT exchange.
index 80564fe03024634dc479280a8fe8d60ea643e1cc..8b9b6790a3dfc60b562a3a6ea30dccf248612cc4 100644 (file)
@@ -736,15 +736,12 @@ static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
 
        epb = &ep->base;
 
-       if (hlist_unhashed(&epb->node))
-               return;
-
        epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);
 
        head = &sctp_ep_hashtable[epb->hashent];
 
        sctp_write_lock(&head->lock);
-       __hlist_del(&epb->node);
+       hlist_del_init(&epb->node);
        sctp_write_unlock(&head->lock);
 }
 
@@ -825,7 +822,7 @@ static void __sctp_unhash_established(struct sctp_association *asoc)
        head = &sctp_assoc_hashtable[epb->hashent];
 
        sctp_write_lock(&head->lock);
-       __hlist_del(&epb->node);
+       hlist_del_init(&epb->node);
        sctp_write_unlock(&head->lock);
 }
 
index f1b7d4bb591e9b648865c4e096ef838e77678442..6ae47acaaec65ceb898e10e462454e667a8e739e 100644 (file)
@@ -248,6 +248,11 @@ static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
                /* If the SACK timer is running, we have a pending SACK */
                if (timer_pending(timer)) {
                        struct sctp_chunk *sack;
+
+                       if (pkt->transport->sack_generation !=
+                           pkt->transport->asoc->peer.sack_generation)
+                               return retval;
+
                        asoc->a_rwnd = asoc->rwnd;
                        sack = sctp_make_sack(asoc);
                        if (sack) {
index a85eeeb55dd0022e009895c53a6d8593929b7691..b6de71efb140c538a66e0a7901df2b4402a85bf4 100644 (file)
@@ -734,8 +734,10 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
        int len;
        __u32 ctsn;
        __u16 num_gabs, num_dup_tsns;
+       struct sctp_association *aptr = (struct sctp_association *)asoc;
        struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
        struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
+       struct sctp_transport *trans;
 
        memset(gabs, 0, sizeof(gabs));
        ctsn = sctp_tsnmap_get_ctsn(map);
@@ -805,6 +807,20 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
                sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
                                 sctp_tsnmap_get_dups(map));
 
+       /* Once we have a sack generated, check to see what our sack
+        * generation is, if its 0, reset the transports to 0, and reset
+        * the association generation to 1
+        *
+        * The idea is that zero is never used as a valid generation for the
+        * association so no transport will match after a wrap event like this,
+        * Until the next sack
+        */
+       if (++aptr->peer.sack_generation == 0) {
+               list_for_each_entry(trans, &asoc->peer.transport_addr_list,
+                                   transports)
+                       trans->sack_generation = 0;
+               aptr->peer.sack_generation = 1;
+       }
 nodata:
        return retval;
 }
index c96d1a81cf4209f6d3ca9b6762fefa47e75867c3..8716da1a859221dc96d206ed517190e9e9cfa2ca 100644 (file)
@@ -1268,7 +1268,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                case SCTP_CMD_REPORT_TSN:
                        /* Record the arrival of a TSN.  */
                        error = sctp_tsnmap_mark(&asoc->peer.tsn_map,
-                                                cmd->obj.u32);
+                                                cmd->obj.u32, NULL);
                        break;
 
                case SCTP_CMD_REPORT_FWDTSN:
index b3b8a8d813eb663f18a6fd488d3f0472f2fe1263..31c7bfcd9b5872aa136e2b513123bb6d582bdff6 100644 (file)
@@ -1231,8 +1231,14 @@ out_free:
        SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p"
                          " kaddrs: %p err: %d\n",
                          asoc, kaddrs, err);
-       if (asoc)
+       if (asoc) {
+               /* sctp_primitive_ASSOCIATE may have added this association
+                * To the hash table, try to unhash it, just in case, its a noop
+                * if it wasn't hashed so we're safe
+                */
+               sctp_unhash_established(asoc);
                sctp_association_free(asoc);
+       }
        return err;
 }
 
@@ -1942,8 +1948,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        goto out_unlock;
 
 out_free:
-       if (new_asoc)
+       if (new_asoc) {
+               sctp_unhash_established(asoc);
                sctp_association_free(asoc);
+       }
 out_unlock:
        sctp_release_sock(sk);
 
index b026ba0c69922e09eb5c150298f650ea7bb3d1c4..1dcceb6e0ce6c2b9e5f6c0c3abf8075c3e75224c 100644 (file)
@@ -68,6 +68,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
        peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
        memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
+       peer->sack_generation = 0;
+
        /* From 6.3.1 RTO Calculation:
         *
         * C1) Until an RTT measurement has been made for a packet sent to the
index f1e40cebc981ae7962bb9cd20ae84823b70d43cf..b5fb7c409023ff8adea81d41e68ace60781febae 100644 (file)
@@ -114,7 +114,8 @@ int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 
 
 /* Mark this TSN as seen.  */
-int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
+int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
+                    struct sctp_transport *trans)
 {
        u16 gap;
 
@@ -133,6 +134,9 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
                 */
                map->max_tsn_seen++;
                map->cumulative_tsn_ack_point++;
+               if (trans)
+                       trans->sack_generation =
+                               trans->asoc->peer.sack_generation;
                map->base_tsn++;
        } else {
                /* Either we already have a gap, or about to record a gap, so
index 8a84017834c211a840e83c1e39bebdbb001ec5c4..33d894776192205cd4b4a9573ccf70664c723b2d 100644 (file)
@@ -715,7 +715,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
         * can mark it as received so the tsn_map is updated correctly.
         */
        if (sctp_tsnmap_mark(&asoc->peer.tsn_map,
-                            ntohl(chunk->subh.data_hdr->tsn)))
+                            ntohl(chunk->subh.data_hdr->tsn),
+                            chunk->transport))
                goto fail_mark;
 
        /* First calculate the padding, so we don't inadvertently
index f2d1de7f2ffbd5a219759f55bdc546f2edbf19b0..f5a6a4f4faf721af4874538093cb003f4efc202c 100644 (file)
@@ -1051,7 +1051,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
        if (chunk && (freed >= needed)) {
                __u32 tsn;
                tsn = ntohl(chunk->subh.data_hdr->tsn);
-               sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+               sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
                sctp_ulpq_tail_data(ulpq, chunk, gfp);
 
                sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
index 3dcbf86b0d31b9c7c9c889c80dacf34f9b33adc6..c246ba5d43ab9474a28fab01c11b6ae5cb20d99a 100644 (file)
@@ -149,7 +149,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
 #define KEY_LOOKUP_FOR_UNLINK  0x04
 
 extern long join_session_keyring(const char *name);
-extern void key_change_session_keyring(struct task_work *twork);
+extern void key_change_session_keyring(struct callback_head *twork);
 
 extern struct work_struct key_gc_work;
 extern unsigned key_gc_delay;
index 0f5b3f0272995dc7057f1306c346468174d3e464..f1b59ae39d7ee1ac1cbf518ecbc5a6644276442f 100644 (file)
@@ -1456,7 +1456,7 @@ long keyctl_session_to_parent(void)
 {
        struct task_struct *me, *parent;
        const struct cred *mycred, *pcred;
-       struct task_work *newwork, *oldwork;
+       struct callback_head *newwork, *oldwork;
        key_ref_t keyring_r;
        struct cred *cred;
        int ret;
@@ -1466,19 +1466,17 @@ long keyctl_session_to_parent(void)
                return PTR_ERR(keyring_r);
 
        ret = -ENOMEM;
-       newwork = kmalloc(sizeof(struct task_work), GFP_KERNEL);
-       if (!newwork)
-               goto error_keyring;
 
        /* our parent is going to need a new cred struct, a new tgcred struct
         * and new security data, so we allocate them here to prevent ENOMEM in
         * our parent */
        cred = cred_alloc_blank();
        if (!cred)
-               goto error_newwork;
+               goto error_keyring;
+       newwork = &cred->rcu;
 
        cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
-       init_task_work(newwork, key_change_session_keyring, cred);
+       init_task_work(newwork, key_change_session_keyring);
 
        me = current;
        rcu_read_lock();
@@ -1488,6 +1486,7 @@ long keyctl_session_to_parent(void)
        oldwork = NULL;
        parent = me->real_parent;
 
+       task_lock(parent);
        /* the parent mustn't be init and mustn't be a kernel thread */
        if (parent->pid <= 1 || !parent->mm)
                goto unlock;
@@ -1531,20 +1530,15 @@ long keyctl_session_to_parent(void)
        if (!ret)
                newwork = NULL;
 unlock:
+       task_unlock(parent);
        write_unlock_irq(&tasklist_lock);
        rcu_read_unlock();
-       if (oldwork) {
-               put_cred(oldwork->data);
-               kfree(oldwork);
-       }
-       if (newwork) {
-               put_cred(newwork->data);
-               kfree(newwork);
-       }
+       if (oldwork)
+               put_cred(container_of(oldwork, struct cred, rcu));
+       if (newwork)
+               put_cred(cred);
        return ret;
 
-error_newwork:
-       kfree(newwork);
 error_keyring:
        key_ref_put(keyring_r);
        return ret;
index 4ad54eea1ea45554d5d931497671fdb32a33660b..54339cfd6734d46927e8e9228019891e7130c272 100644 (file)
@@ -834,12 +834,11 @@ error:
  * Replace a process's session keyring on behalf of one of its children when
  * the target  process is about to resume userspace execution.
  */
-void key_change_session_keyring(struct task_work *twork)
+void key_change_session_keyring(struct callback_head *twork)
 {
        const struct cred *old = current_cred();
-       struct cred *new = twork->data;
+       struct cred *new = container_of(twork, struct cred, rcu);
 
-       kfree(twork);
        if (unlikely(current->flags & PF_EXITING)) {
                put_cred(new);
                return;
index 3efc9b12aef44016201b02eeafcc10140f17a240..860aeb349cb337bbccf4346d99120d4d1fd51c90 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mman.h>
 #include <linux/mount.h>
 #include <linux/personality.h>
+#include <linux/backing-dev.h>
 #include <net/flow.h>
 
 #define MAX_LSM_EVM_XATTR      2
index 372ec6502aa8752dca83c3c507e2d0ce9cac84d1..9292a8971e66d690b819160588f46aebce2fbdf1 100644 (file)
@@ -2157,8 +2157,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
                                                get_file(devnull);
                                        } else {
                                                devnull = dentry_open(
-                                                       dget(selinux_null),
-                                                       mntget(selinuxfs_mount),
+                                                       &selinux_null,
                                                        O_RDWR, cred);
                                                if (IS_ERR(devnull)) {
                                                        devnull = NULL;
@@ -2717,7 +2716,7 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
                        ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
                return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-       if (ia_valid & ATTR_SIZE)
+       if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE))
                av |= FILE__OPEN;
 
        return dentry_has_perm(cred, dentry, av);
index b8c53723e09bfe7d6c211bc05df35793ae9ac8b2..df2de54a958debfab56caf3483cd5d93856e5be4 100644 (file)
@@ -145,7 +145,9 @@ struct security_class_mapping secclass_map[] = {
            "node_bind", "name_connect", NULL } },
        { "memprotect", { "mmap_zero", NULL } },
        { "peer", { "recv", NULL } },
-       { "capability2", { "mac_override", "mac_admin", "syslog", NULL } },
+       { "capability2",
+         { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend",
+           NULL } },
        { "kernel_service", { "use_as_override", "create_files_as", NULL } },
        { "tun_socket",
          { COMMON_SOCK_PERMS, NULL } },
index dde2005407aa5343dd92fe0e91e4b1a0d68ee33d..6d3885165d143a27fb218e785aa4a13ac7937045 100644 (file)
@@ -221,7 +221,7 @@ extern void selinux_status_update_policyload(int seqno);
 extern void selinux_complete_init(void);
 extern int selinux_disable(void);
 extern void exit_sel_fs(void);
-extern struct dentry *selinux_null;
+extern struct path selinux_null;
 extern struct vfsmount *selinuxfs_mount;
 extern void selnl_notify_setenforce(int val);
 extern void selnl_notify_policyload(u32 seqno);
index 3ad2902512888282e299b64434a7790d9788e060..298e695d6822577e80e5a03a3b5b77d78fe9ebc8 100644 (file)
@@ -1297,7 +1297,7 @@ out:
 
 #define NULL_FILE_NAME "null"
 
-struct dentry *selinux_null;
+struct path selinux_null;
 
 static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
                                            size_t count, loff_t *ppos)
@@ -1838,7 +1838,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
 
        init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
        d_add(dentry, inode);
-       selinux_null = dentry;
+       selinux_null.dentry = dentry;
 
        dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino);
        if (IS_ERR(dentry)) {
@@ -1912,7 +1912,7 @@ static int __init init_sel_fs(void)
                return err;
        }
 
-       selinuxfs_mount = kern_mount(&sel_fs_type);
+       selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
        if (IS_ERR(selinuxfs_mount)) {
                printk(KERN_ERR "selinuxfs:  could not mount!\n");
                err = PTR_ERR(selinuxfs_mount);
index 5ccf10a4d5932b187bba679e40e8f424d4739551..aa4c25e0f3277fce38520c72c9759bfc90b9022d 100644 (file)
@@ -6688,6 +6688,31 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
        {}
 };
 
+static void alc662_fill_coef(struct hda_codec *codec)
+{
+       int val, coef;
+
+       coef = alc_get_coef0(codec);
+
+       switch (codec->vendor_id) {
+       case 0x10ec0662:
+               if ((coef & 0x00f0) == 0x0030) {
+                       val = alc_read_coef_idx(codec, 0x4); /* EAPD Ctrl */
+                       alc_write_coef_idx(codec, 0x4, val & ~(1<<10));
+               }
+               break;
+       case 0x10ec0272:
+       case 0x10ec0273:
+       case 0x10ec0663:
+       case 0x10ec0665:
+       case 0x10ec0670:
+       case 0x10ec0671:
+       case 0x10ec0672:
+               val = alc_read_coef_idx(codec, 0xd); /* EAPD Ctrl */
+               alc_write_coef_idx(codec, 0xd, val | (1<<14));
+               break;
+       }
+}
 
 /*
  */
@@ -6707,6 +6732,9 @@ static int patch_alc662(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+       spec->init_hook = alc662_fill_coef;
+       alc662_fill_coef(codec);
+
        alc_pick_fixup(codec, alc662_fixup_models,
                       alc662_fixup_tbl, alc662_fixups);
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
index 64d2a4fa34b27d81ad84d0e64ed625e04e293b7a..e9b62b5ea637580ea7e8904ec2c68662ed1471fc 100644 (file)
@@ -935,9 +935,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        }
 
 found:
-       data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
-       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
-                     data | (pll_p << PLLP_SHIFT));
+       snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p);
        snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
                      pll_r << PLLR_SHIFT);
        snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
index 6f097fb60683e7b5605b38e373c7f1c75f4158c9..08c7f6685ff0937a367824c7a731fd4fb8e48d72 100644 (file)
 
 /* PLL registers bitfields */
 #define PLLP_SHIFT             0
+#define PLLP_MASK              7
 #define PLLQ_SHIFT             3
 #define PLLR_SHIFT             0
 #define PLLJ_SHIFT             2
index acbdc5fde9236be0e43a5767bd0135eb92450e68..32682c1b7cdece413693db6f6487ae4df640da09 100644 (file)
@@ -1491,6 +1491,7 @@ static int wm2200_bclk_rates_dat[WM2200_NUM_BCLK_RATES] = {
 
 static int wm2200_bclk_rates_cd[WM2200_NUM_BCLK_RATES] = {
        5644800,
+       3763200,
        2882400,
        1881600,
        1411200,
index ddc6cde14e2a588763531d94f22b0dab2b1d9a49..f3ebc38c10fe7633ea5ec260562b64bfdb7e402f 100644 (file)
@@ -74,7 +74,7 @@ static void dma_enqueue(struct snd_pcm_substream *substream)
        struct runtime_data *prtd = substream->runtime->private_data;
        dma_addr_t pos = prtd->dma_pos;
        unsigned int limit;
-       struct samsung_dma_prep_info dma_info;
+       struct samsung_dma_prep dma_info;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -146,7 +146,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
        unsigned long totbytes = params_buffer_bytes(params);
        struct s3c_dma_params *dma =
                snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       struct samsung_dma_info dma_info;
+       struct samsung_dma_req req;
+       struct samsung_dma_config config;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -166,16 +167,17 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
 
                prtd->params->ops = samsung_dma_get_ops();
 
-               dma_info.cap = (samsung_dma_has_circular() ?
+               req.cap = (samsung_dma_has_circular() ?
                        DMA_CYCLIC : DMA_SLAVE);
-               dma_info.client = prtd->params->client;
-               dma_info.direction =
+               req.client = prtd->params->client;
+               config.direction =
                        (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
                        ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
-               dma_info.width = prtd->params->dma_size;
-               dma_info.fifo = prtd->params->dma_addr;
+               config.width = prtd->params->dma_size;
+               config.fifo = prtd->params->dma_addr;
                prtd->params->ch = prtd->params->ops->request(
-                               prtd->params->channel, &dma_info);
+                               prtd->params->channel, &req);
+               prtd->params->ops->config(prtd->params->ch, &config);
        }
 
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
index c1c8e955f4d31b2a79be704d7dda736bd1e24010..76dc230f2bb05e42e430535be777200fd457e537 100644 (file)
@@ -58,17 +58,9 @@ config SND_SOC_TEGRA_WM8753
          Say Y or M here if you want to add support for SoC audio on Tegra
          boards using the WM8753 codec, such as Whistler.
 
-config MACH_HAS_SND_SOC_TEGRA_WM8903
-       bool
-       help
-         Machines that use the SND_SOC_TEGRA_WM8903 driver should select
-         this config option, in order to allow the user to enable
-         SND_SOC_TEGRA_WM8903.
-
 config SND_SOC_TEGRA_WM8903
        tristate "SoC Audio support for Tegra boards using a WM8903 codec"
        depends on SND_SOC_TEGRA && I2C
-       depends on MACH_HAS_SND_SOC_TEGRA_WM8903
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_WM8903
@@ -79,7 +71,7 @@ config SND_SOC_TEGRA_WM8903
 
 config SND_SOC_TEGRA_TRIMSLICE
        tristate "SoC Audio support for TrimSlice board"
-       depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
+       depends on SND_SOC_TEGRA && I2C
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TLV320AIC23
        help
index e6906901debbc2aaa71c40621fbd4241d8d15663..0f647d22cb4ac7bccffe25311011255cf0b33104 100644 (file)
@@ -414,7 +414,7 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
 {
        struct list_head *p;
        struct snd_usb_endpoint *ep;
-       int ret, is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
+       int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
 
        mutex_lock(&chip->mutex);
 
@@ -434,16 +434,6 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
                    type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
                    ep_num);
 
-       /* select the alt setting once so the endpoints become valid */
-       ret = usb_set_interface(chip->dev, alts->desc.bInterfaceNumber,
-                               alts->desc.bAlternateSetting);
-       if (ret < 0) {
-               snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
-                                       __func__, ret);
-               ep = NULL;
-               goto __exit_unlock;
-       }
-
        ep = kzalloc(sizeof(*ep), GFP_KERNEL);
        if (!ep)
                goto __exit_unlock;
@@ -831,9 +821,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
        if (++ep->use_count != 1)
                return 0;
 
-       if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
-               return -EINVAL;
-
        /* just to be sure */
        deactivate_urbs(ep, 0, 1);
        wait_clear_urbs(ep);
@@ -911,9 +898,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
        if (snd_BUG_ON(ep->use_count == 0))
                return;
 
-       if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
-               return;
-
        if (--ep->use_count == 0) {
                deactivate_urbs(ep, force, can_sleep);
                ep->data_subs = NULL;
@@ -926,42 +910,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
        }
 }
 
-/**
- * snd_usb_endpoint_activate: activate an snd_usb_endpoint
- *
- * @ep: the endpoint to activate
- *
- * If the endpoint is not currently in use, this functions will select the
- * correct alternate interface setting for the interface of this endpoint.
- *
- * In case of any active users, this functions does nothing.
- *
- * Returns an error if usb_set_interface() failed, 0 in all other
- * cases.
- */
-int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep)
-{
-       if (ep->use_count != 0)
-               return 0;
-
-       if (!ep->chip->shutdown &&
-           !test_and_set_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
-               int ret;
-
-               ret = usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
-               if (ret < 0) {
-                       snd_printk(KERN_ERR "%s() usb_set_interface() failed, ret = %d\n",
-                                               __func__, ret);
-                       clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
-                       return ret;
-               }
-
-               return 0;
-       }
-
-       return -EBUSY;
-}
-
 /**
  * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint
  *
@@ -980,24 +928,15 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
        if (!ep)
                return -EINVAL;
 
+       deactivate_urbs(ep, 1, 1);
+       wait_clear_urbs(ep);
+
        if (ep->use_count != 0)
                return 0;
 
-       if (!ep->chip->shutdown &&
-           test_and_clear_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
-               int ret;
-
-               ret = usb_set_interface(ep->chip->dev, ep->iface, 0);
-               if (ret < 0) {
-                       snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
-                                               __func__, ret);
-                       return ret;
-               }
+       clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
 
-               return 0;
-       }
-
-       return -EBUSY;
+       return 0;
 }
 
 /**
index 54607f8c4f66ca91e5502808aa9fc94ceebc4d76..a1298f379428280045bf661f89e5fa59bb0acb48 100644 (file)
@@ -261,19 +261,6 @@ static void stop_endpoints(struct snd_usb_substream *subs,
                                      force, can_sleep, wait);
 }
 
-static int activate_endpoints(struct snd_usb_substream *subs)
-{
-       if (subs->sync_endpoint) {
-               int ret;
-
-               ret = snd_usb_endpoint_activate(subs->sync_endpoint);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return snd_usb_endpoint_activate(subs->data_endpoint);
-}
-
 static int deactivate_endpoints(struct snd_usb_substream *subs)
 {
        int reta, retb;
@@ -314,6 +301,33 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
        if (fmt == subs->cur_audiofmt)
                return 0;
 
+       /* close the old interface */
+       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);
+                       return -EIO;
+               }
+               subs->interface = -1;
+               subs->altset_idx = 0;
+       }
+
+       /* set interface */
+       if (subs->interface != fmt->iface ||
+           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);
+                       return -EIO;
+               }
+               snd_printdd(KERN_INFO "setting usb interface %d:%d\n",
+                               fmt->iface, fmt->altsetting);
+               subs->interface = fmt->iface;
+               subs->altset_idx = fmt->altset_idx;
+       }
+
        subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
                                                   alts, fmt->endpoint, subs->direction,
                                                   SND_USB_ENDPOINT_TYPE_DATA);
@@ -387,7 +401,7 @@ add_sync_ep:
                subs->data_endpoint->sync_master = subs->sync_endpoint;
        }
 
-       if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
+       if ((err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt)) < 0)
                return err;
 
        subs->cur_audiofmt = fmt;
@@ -450,7 +464,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
                struct usb_interface *iface;
                iface = usb_ifnum_to_if(subs->dev, fmt->iface);
                alts = &iface->altsetting[fmt->altset_idx];
-               ret = snd_usb_init_sample_rate(subs->stream->chip, subs->interface, alts, fmt, rate);
+               ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate);
                if (ret < 0)
                        return ret;
                subs->cur_rate = rate;
@@ -460,12 +474,6 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
                mutex_lock(&subs->stream->chip->shutdown_mutex);
                /* format changed */
                stop_endpoints(subs, 0, 0, 0);
-               deactivate_endpoints(subs);
-
-               ret = activate_endpoints(subs);
-               if (ret < 0)
-                       goto unlock;
-
                ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
                                                  subs->sync_endpoint);
                if (ret < 0)
@@ -500,6 +508,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        subs->period_bytes = 0;
        mutex_lock(&subs->stream->chip->shutdown_mutex);
        stop_endpoints(subs, 0, 1, 1);
+       deactivate_endpoints(subs);
        mutex_unlock(&subs->stream->chip->shutdown_mutex);
        return snd_pcm_lib_free_vmalloc_buffer(substream);
 }
@@ -938,16 +947,20 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
 
 static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
 {
-       int ret;
        struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
        struct snd_usb_substream *subs = &as->substream[direction];
 
        stop_endpoints(subs, 0, 0, 0);
-       ret = deactivate_endpoints(subs);
+
+       if (!as->chip->shutdown && subs->interface >= 0) {
+               usb_set_interface(subs->dev, subs->interface, 0);
+               subs->interface = -1;
+       }
+
        subs->pcm_substream = NULL;
        snd_usb_autosuspend(subs->stream->chip);
 
-       return ret;
+       return 0;
 }
 
 /* Since a URB can handle only a single linear buffer, we must use double
index 3d69aa9ff51e8ff336cae400860a4b544dc82fe3..46c2f6b7b123c388d056ae6c324cdde76edef182 100644 (file)
@@ -250,8 +250,12 @@ endef
 all_objs := $(sort $(ALL_OBJS))
 all_deps := $(all_objs:%.o=.%.d)
 
+# let .d file also depends on the source and header files
 define check_deps
-               $(CC) -M $(CFLAGS) $< > $@;
+               @set -e; $(RM) $@; \
+               $(CC) -M $(CFLAGS) $< > $@.$$$$; \
+               sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+               $(RM) $@.$$$$
 endef
 
 $(gui_deps): ks_version.h
@@ -270,11 +274,13 @@ endif
 
 tags:  force
        $(RM) tags
-       find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px
+       find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
+       --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
 
 TAGS:  force
        $(RM) TAGS
-       find . -name '*.[ch]' | xargs etags
+       find . -name '*.[ch]' | xargs etags \
+       --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
 
 define do_install
        $(print_install)                                \
@@ -290,7 +296,7 @@ install_lib: all_cmd install_plugins install_python
 install: install_lib
 
 clean:
-       $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d
+       $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
        $(RM) tags TAGS
 
 endif # skip-makefile
index 554828219c33cceaf0c5b9d3f57bd69d4a7a109f..5f34aa371b5660c503cfca05e9e0731aba013ea7 100644 (file)
@@ -467,8 +467,10 @@ int pevent_register_function(struct pevent *pevent, char *func,
                item->mod = NULL;
        item->addr = addr;
 
-       pevent->funclist = item;
+       if (!item->func || (mod && !item->mod))
+               die("malloc func");
 
+       pevent->funclist = item;
        pevent->func_count++;
 
        return 0;
@@ -511,12 +513,12 @@ struct printk_list {
 
 static int printk_cmp(const void *a, const void *b)
 {
-       const struct func_map *fa = a;
-       const struct func_map *fb = b;
+       const struct printk_map *pa = a;
+       const struct printk_map *pb = b;
 
-       if (fa->addr < fb->addr)
+       if (pa->addr < pb->addr)
                return -1;
-       if (fa->addr > fb->addr)
+       if (pa->addr > pb->addr)
                return 1;
 
        return 0;
@@ -583,10 +585,13 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
        item = malloc_or_die(sizeof(*item));
 
        item->next = pevent->printklist;
-       pevent->printklist = item;
        item->printk = strdup(fmt);
        item->addr = addr;
 
+       if (!item->printk)
+               die("malloc fmt");
+
+       pevent->printklist = item;
        pevent->printk_count++;
 
        return 0;
@@ -616,7 +621,9 @@ static struct event_format *alloc_event(void)
 {
        struct event_format *event;
 
-       event = malloc_or_die(sizeof(*event));
+       event = malloc(sizeof(*event));
+       if (!event)
+               return NULL;
        memset(event, 0, sizeof(*event));
 
        return event;
@@ -626,12 +633,8 @@ static void add_event(struct pevent *pevent, struct event_format *event)
 {
        int i;
 
-       if (!pevent->events)
-               pevent->events = malloc_or_die(sizeof(event));
-       else
-               pevent->events =
-                       realloc(pevent->events, sizeof(event) *
-                               (pevent->nr_events + 1));
+       pevent->events = realloc(pevent->events, sizeof(event) *
+                                (pevent->nr_events + 1));
        if (!pevent->events)
                die("Can not allocate events");
 
@@ -697,6 +700,10 @@ static void free_arg(struct print_arg *arg)
                free_arg(arg->symbol.field);
                free_flag_sym(arg->symbol.symbols);
                break;
+       case PRINT_HEX:
+               free_arg(arg->hex.field);
+               free_arg(arg->hex.size);
+               break;
        case PRINT_TYPE:
                free(arg->typecast.type);
                free_arg(arg->typecast.item);
@@ -775,6 +782,25 @@ int pevent_peek_char(void)
        return __peek_char();
 }
 
+static int extend_token(char **tok, char *buf, int size)
+{
+       char *newtok = realloc(*tok, size);
+
+       if (!newtok) {
+               free(*tok);
+               *tok = NULL;
+               return -1;
+       }
+
+       if (!*tok)
+               strcpy(newtok, buf);
+       else
+               strcat(newtok, buf);
+       *tok = newtok;
+
+       return 0;
+}
+
 static enum event_type force_token(const char *str, char **tok);
 
 static enum event_type __read_token(char **tok)
@@ -859,17 +885,10 @@ static enum event_type __read_token(char **tok)
                do {
                        if (i == (BUFSIZ - 1)) {
                                buf[i] = 0;
-                               if (*tok) {
-                                       *tok = realloc(*tok, tok_size + BUFSIZ);
-                                       if (!*tok)
-                                               return EVENT_NONE;
-                                       strcat(*tok, buf);
-                               } else
-                                       *tok = strdup(buf);
+                               tok_size += BUFSIZ;
 
-                               if (!*tok)
+                               if (extend_token(tok, buf, tok_size) < 0)
                                        return EVENT_NONE;
-                               tok_size += BUFSIZ;
                                i = 0;
                        }
                        last_ch = ch;
@@ -908,17 +927,10 @@ static enum event_type __read_token(char **tok)
        while (get_type(__peek_char()) == type) {
                if (i == (BUFSIZ - 1)) {
                        buf[i] = 0;
-                       if (*tok) {
-                               *tok = realloc(*tok, tok_size + BUFSIZ);
-                               if (!*tok)
-                                       return EVENT_NONE;
-                               strcat(*tok, buf);
-                       } else
-                               *tok = strdup(buf);
+                       tok_size += BUFSIZ;
 
-                       if (!*tok)
+                       if (extend_token(tok, buf, tok_size) < 0)
                                return EVENT_NONE;
-                       tok_size += BUFSIZ;
                        i = 0;
                }
                ch = __read_char();
@@ -927,14 +939,7 @@ static enum event_type __read_token(char **tok)
 
  out:
        buf[i] = 0;
-       if (*tok) {
-               *tok = realloc(*tok, tok_size + i);
-               if (!*tok)
-                       return EVENT_NONE;
-               strcat(*tok, buf);
-       } else
-               *tok = strdup(buf);
-       if (!*tok)
+       if (extend_token(tok, buf, tok_size + i + 1) < 0)
                return EVENT_NONE;
 
        if (type == EVENT_ITEM) {
@@ -1255,9 +1260,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                                        field->flags |= FIELD_IS_POINTER;
 
                                if (field->type) {
-                                       field->type = realloc(field->type,
-                                                             strlen(field->type) +
-                                                             strlen(last_token) + 2);
+                                       char *new_type;
+                                       new_type = realloc(field->type,
+                                                          strlen(field->type) +
+                                                          strlen(last_token) + 2);
+                                       if (!new_type) {
+                                               free(last_token);
+                                               goto fail;
+                                       }
+                                       field->type = new_type;
                                        strcat(field->type, " ");
                                        strcat(field->type, last_token);
                                        free(last_token);
@@ -1282,6 +1293,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                if (strcmp(token, "[") == 0) {
                        enum event_type last_type = type;
                        char *brackets = token;
+                       char *new_brackets;
                        int len;
 
                        field->flags |= FIELD_IS_ARRAY;
@@ -1301,9 +1313,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                                        len = 1;
                                last_type = type;
 
-                               brackets = realloc(brackets,
-                                                  strlen(brackets) +
-                                                  strlen(token) + len);
+                               new_brackets = realloc(brackets,
+                                                      strlen(brackets) +
+                                                      strlen(token) + len);
+                               if (!new_brackets) {
+                                       free(brackets);
+                                       goto fail;
+                               }
+                               brackets = new_brackets;
                                if (len == 2)
                                        strcat(brackets, " ");
                                strcat(brackets, token);
@@ -1319,7 +1336,12 @@ static int event_read_fields(struct event_format *event, struct format_field **f
 
                        free_token(token);
 
-                       brackets = realloc(brackets, strlen(brackets) + 2);
+                       new_brackets = realloc(brackets, strlen(brackets) + 2);
+                       if (!new_brackets) {
+                               free(brackets);
+                               goto fail;
+                       }
+                       brackets = new_brackets;
                        strcat(brackets, "]");
 
                        /* add brackets to type */
@@ -1330,10 +1352,16 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                         * the format: type [] item;
                         */
                        if (type == EVENT_ITEM) {
-                               field->type = realloc(field->type,
-                                                     strlen(field->type) +
-                                                     strlen(field->name) +
-                                                     strlen(brackets) + 2);
+                               char *new_type;
+                               new_type = realloc(field->type,
+                                                  strlen(field->type) +
+                                                  strlen(field->name) +
+                                                  strlen(brackets) + 2);
+                               if (!new_type) {
+                                       free(brackets);
+                                       goto fail;
+                               }
+                               field->type = new_type;
                                strcat(field->type, " ");
                                strcat(field->type, field->name);
                                free_token(field->name);
@@ -1341,9 +1369,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                                field->name = token;
                                type = read_token(&token);
                        } else {
-                               field->type = realloc(field->type,
-                                                     strlen(field->type) +
-                                                     strlen(brackets) + 1);
+                               char *new_type;
+                               new_type = realloc(field->type,
+                                                  strlen(field->type) +
+                                                  strlen(brackets) + 1);
+                               if (!new_type) {
+                                       free(brackets);
+                                       goto fail;
+                               }
+                               field->type = new_type;
                                strcat(field->type, brackets);
                        }
                        free(brackets);
@@ -1726,10 +1760,16 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
                /* could just be a type pointer */
                if ((strcmp(arg->op.op, "*") == 0) &&
                    type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
+                       char *new_atom;
+
                        if (left->type != PRINT_ATOM)
                                die("bad pointer type");
-                       left->atom.atom = realloc(left->atom.atom,
+                       new_atom = realloc(left->atom.atom,
                                            strlen(left->atom.atom) + 3);
+                       if (!new_atom)
+                               goto out_free;
+
+                       left->atom.atom = new_atom;
                        strcat(left->atom.atom, " *");
                        free(arg->op.op);
                        *arg = *left;
@@ -2146,6 +2186,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char **
                if (value == NULL)
                        goto out_free;
                field->value = strdup(value);
+               if (field->value == NULL)
+                       goto out_free;
 
                free_arg(arg);
                arg = alloc_arg();
@@ -2159,6 +2201,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char **
                if (value == NULL)
                        goto out_free;
                field->str = strdup(value);
+               if (field->str == NULL)
+                       goto out_free;
                free_arg(arg);
                arg = NULL;
 
@@ -2259,6 +2303,45 @@ process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
        return EVENT_ERROR;
 }
 
+static enum event_type
+process_hex(struct event_format *event, struct print_arg *arg, char **tok)
+{
+       struct print_arg *field;
+       enum event_type type;
+       char *token;
+
+       memset(arg, 0, sizeof(*arg));
+       arg->type = PRINT_HEX;
+
+       field = alloc_arg();
+       type = process_arg(event, field, &token);
+
+       if (test_type_token(type, token, EVENT_DELIM, ","))
+               goto out_free;
+
+       arg->hex.field = field;
+
+       free_token(token);
+
+       field = alloc_arg();
+       type = process_arg(event, field, &token);
+
+       if (test_type_token(type, token, EVENT_DELIM, ")"))
+               goto out_free;
+
+       arg->hex.size = field;
+
+       free_token(token);
+       type = read_token_item(tok);
+       return type;
+
+ out_free:
+       free_arg(field);
+       free_token(token);
+       *tok = NULL;
+       return EVENT_ERROR;
+}
+
 static enum event_type
 process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
 {
@@ -2488,6 +2571,10 @@ process_function(struct event_format *event, struct print_arg *arg,
                is_symbolic_field = 1;
                return process_symbols(event, arg, tok);
        }
+       if (strcmp(token, "__print_hex") == 0) {
+               free_token(token);
+               return process_hex(event, arg, tok);
+       }
        if (strcmp(token, "__get_str") == 0) {
                free_token(token);
                return process_str(event, arg, tok);
@@ -2541,7 +2628,16 @@ process_arg_token(struct event_format *event, struct print_arg *arg,
                }
                /* atoms can be more than one token long */
                while (type == EVENT_ITEM) {
-                       atom = realloc(atom, strlen(atom) + strlen(token) + 2);
+                       char *new_atom;
+                       new_atom = realloc(atom,
+                                          strlen(atom) + strlen(token) + 2);
+                       if (!new_atom) {
+                               free(atom);
+                               *tok = NULL;
+                               free_token(token);
+                               return EVENT_ERROR;
+                       }
+                       atom = new_atom;
                        strcat(atom, " ");
                        strcat(atom, token);
                        free_token(token);
@@ -2835,7 +2931,7 @@ static int get_common_info(struct pevent *pevent,
        event = pevent->events[0];
        field = pevent_find_common_field(event, type);
        if (!field)
-               die("field '%s' not found", type);
+               return -1;
 
        *offset = field->offset;
        *size = field->size;
@@ -2886,15 +2982,16 @@ static int parse_common_flags(struct pevent *pevent, void *data)
 
 static int parse_common_lock_depth(struct pevent *pevent, void *data)
 {
-       int ret;
-
-       ret = __parse_common(pevent, data,
-                            &pevent->ld_size, &pevent->ld_offset,
-                            "common_lock_depth");
-       if (ret < 0)
-               return -1;
+       return __parse_common(pevent, data,
+                             &pevent->ld_size, &pevent->ld_offset,
+                             "common_lock_depth");
+}
 
-       return ret;
+static int parse_common_migrate_disable(struct pevent *pevent, void *data)
+{
+       return __parse_common(pevent, data,
+                             &pevent->ld_size, &pevent->ld_offset,
+                             "common_migrate_disable");
 }
 
 static int events_id_cmp(const void *a, const void *b);
@@ -2995,6 +3092,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
                break;
        case PRINT_FLAGS:
        case PRINT_SYMBOL:
+       case PRINT_HEX:
                break;
        case PRINT_TYPE:
                val = eval_num_arg(data, size, event, arg->typecast.item);
@@ -3214,11 +3312,13 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
 {
        struct pevent *pevent = event->pevent;
        struct print_flag_sym *flag;
+       struct format_field *field;
        unsigned long long val, fval;
        unsigned long addr;
        char *str;
+       unsigned char *hex;
        int print;
-       int len;
+       int i, len;
 
        switch (arg->type) {
        case PRINT_NULL:
@@ -3228,27 +3328,29 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
                print_str_to_seq(s, format, len_arg, arg->atom.atom);
                return;
        case PRINT_FIELD:
-               if (!arg->field.field) {
-                       arg->field.field = pevent_find_any_field(event, arg->field.name);
-                       if (!arg->field.field)
+               field = arg->field.field;
+               if (!field) {
+                       field = pevent_find_any_field(event, arg->field.name);
+                       if (!field)
                                die("field %s not found", arg->field.name);
+                       arg->field.field = field;
                }
                /* Zero sized fields, mean the rest of the data */
-               len = arg->field.field->size ? : size - arg->field.field->offset;
+               len = field->size ? : size - field->offset;
 
                /*
                 * Some events pass in pointers. If this is not an array
                 * and the size is the same as long_size, assume that it
                 * is a pointer.
                 */
-               if (!(arg->field.field->flags & FIELD_IS_ARRAY) &&
-                   arg->field.field->size == pevent->long_size) {
-                       addr = *(unsigned long *)(data + arg->field.field->offset);
+               if (!(field->flags & FIELD_IS_ARRAY) &&
+                   field->size == pevent->long_size) {
+                       addr = *(unsigned long *)(data + field->offset);
                        trace_seq_printf(s, "%lx", addr);
                        break;
                }
                str = malloc_or_die(len + 1);
-               memcpy(str, data + arg->field.field->offset, len);
+               memcpy(str, data + field->offset, len);
                str[len] = 0;
                print_str_to_seq(s, format, len_arg, str);
                free(str);
@@ -3281,6 +3383,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
                        }
                }
                break;
+       case PRINT_HEX:
+               field = arg->hex.field->field.field;
+               if (!field) {
+                       str = arg->hex.field->field.name;
+                       field = pevent_find_any_field(event, str);
+                       if (!field)
+                               die("field %s not found", str);
+                       arg->hex.field->field.field = field;
+               }
+               hex = data + field->offset;
+               len = eval_num_arg(data, size, event, arg->hex.size);
+               for (i = 0; i < len; i++) {
+                       if (i)
+                               trace_seq_putc(s, ' ');
+                       trace_seq_printf(s, "%02x", hex[i]);
+               }
+               break;
 
        case PRINT_TYPE:
                break;
@@ -3299,7 +3418,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
                break;
        }
        case PRINT_BSTRING:
-               trace_seq_printf(s, format, arg->string.string);
+               print_str_to_seq(s, format, len_arg, arg->string.string);
                break;
        case PRINT_OP:
                /*
@@ -3363,6 +3482,10 @@ process_defined_func(struct trace_seq *s, void *data, int size,
                        string = malloc_or_die(sizeof(*string));
                        string->next = strings;
                        string->str = strdup(str.buffer);
+                       if (!string->str)
+                               die("malloc str");
+
+                       args[i] = (unsigned long long)string->str;
                        strings = string;
                        trace_seq_destroy(&str);
                        break;
@@ -3400,6 +3523,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
        unsigned long long ip, val;
        char *ptr;
        void *bptr;
+       int vsize;
 
        field = pevent->bprint_buf_field;
        ip_field = pevent->bprint_ip_field;
@@ -3448,6 +3572,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
                                goto process_again;
                        case '0' ... '9':
                                goto process_again;
+                       case '.':
+                               goto process_again;
                        case 'p':
                                ls = 1;
                                /* fall through */
@@ -3455,23 +3581,30 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
                        case 'u':
                        case 'x':
                        case 'i':
-                               /* the pointers are always 4 bytes aligned */
-                               bptr = (void *)(((unsigned long)bptr + 3) &
-                                               ~3);
                                switch (ls) {
                                case 0:
-                                       ls = 4;
+                                       vsize = 4;
                                        break;
                                case 1:
-                                       ls = pevent->long_size;
+                                       vsize = pevent->long_size;
                                        break;
                                case 2:
-                                       ls = 8;
+                                       vsize = 8;
+                                       break;
                                default:
+                                       vsize = ls; /* ? */
                                        break;
                                }
-                               val = pevent_read_number(pevent, bptr, ls);
-                               bptr += ls;
+                       /* fall through */
+                       case '*':
+                               if (*ptr == '*')
+                                       vsize = 4;
+
+                               /* the pointers are always 4 bytes aligned */
+                               bptr = (void *)(((unsigned long)bptr + 3) &
+                                               ~3);
+                               val = pevent_read_number(pevent, bptr, vsize);
+                               bptr += vsize;
                                arg = alloc_arg();
                                arg->next = NULL;
                                arg->type = PRINT_ATOM;
@@ -3479,12 +3612,21 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
                                sprintf(arg->atom.atom, "%lld", val);
                                *next = arg;
                                next = &arg->next;
+                               /*
+                                * The '*' case means that an arg is used as the length.
+                                * We need to continue to figure out for what.
+                                */
+                               if (*ptr == '*')
+                                       goto process_again;
+
                                break;
                        case 's':
                                arg = alloc_arg();
                                arg->next = NULL;
                                arg->type = PRINT_BSTRING;
                                arg->string.string = strdup(bptr);
+                               if (!arg->string.string)
+                                       break;
                                bptr += strlen(bptr) + 1;
                                *next = arg;
                                next = &arg->next;
@@ -3589,6 +3731,16 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
        trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
 }
 
+static int is_printable_array(char *p, unsigned int len)
+{
+       unsigned int i;
+
+       for (i = 0; i < len && p[i]; i++)
+               if (!isprint(p[i]))
+                   return 0;
+       return 1;
+}
+
 static void print_event_fields(struct trace_seq *s, void *data, int size,
                               struct event_format *event)
 {
@@ -3608,7 +3760,8 @@ static void print_event_fields(struct trace_seq *s, void *data, int size,
                                len = offset >> 16;
                                offset &= 0xffff;
                        }
-                       if (field->flags & FIELD_IS_STRING) {
+                       if (field->flags & FIELD_IS_STRING &&
+                           is_printable_array(data + offset, len)) {
                                trace_seq_printf(s, "%s", (char *)data + offset);
                        } else {
                                trace_seq_puts(s, "ARRAY[");
@@ -3619,6 +3772,7 @@ static void print_event_fields(struct trace_seq *s, void *data, int size,
                                                         *((unsigned char *)data + offset + i));
                                }
                                trace_seq_putc(s, ']');
+                               field->flags &= ~FIELD_IS_STRING;
                        }
                } else {
                        val = pevent_read_number(event->pevent, data + field->offset,
@@ -3758,6 +3912,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
                                } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
                                        print_mac_arg(s, *(ptr+1), data, size, event, arg);
                                        ptr++;
+                                       arg = arg->next;
                                        break;
                                }
 
@@ -3794,14 +3949,15 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
                                                break;
                                        }
                                }
-                               if (pevent->long_size == 8 && ls) {
+                               if (pevent->long_size == 8 && ls &&
+                                   sizeof(long) != 8) {
                                        char *p;
 
                                        ls = 2;
                                        /* make %l into %ll */
                                        p = strchr(format, 'l');
                                        if (p)
-                                               memmove(p, p+1, strlen(p)+1);
+                                               memmove(p+1, p, strlen(p)+1);
                                        else if (strcmp(format, "%p") == 0)
                                                strcpy(format, "0x%llx");
                                }
@@ -3878,8 +4034,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
  * pevent_data_lat_fmt - parse the data for the latency format
  * @pevent: a handle to the pevent
  * @s: the trace_seq to write to
- * @data: the raw data to read from
- * @size: currently unused.
+ * @record: the record to read from
  *
  * This parses out the Latency format (interrupts disabled,
  * need rescheduling, in hard/soft interrupt, preempt count
@@ -3889,10 +4044,13 @@ void pevent_data_lat_fmt(struct pevent *pevent,
                         struct trace_seq *s, struct pevent_record *record)
 {
        static int check_lock_depth = 1;
+       static int check_migrate_disable = 1;
        static int lock_depth_exists;
+       static int migrate_disable_exists;
        unsigned int lat_flags;
        unsigned int pc;
        int lock_depth;
+       int migrate_disable;
        int hardirq;
        int softirq;
        void *data = record->data;
@@ -3900,18 +4058,26 @@ void pevent_data_lat_fmt(struct pevent *pevent,
        lat_flags = parse_common_flags(pevent, data);
        pc = parse_common_pc(pevent, data);
        /* lock_depth may not always exist */
-       if (check_lock_depth) {
-               struct format_field *field;
-               struct event_format *event;
-
-               check_lock_depth = 0;
-               event = pevent->events[0];
-               field = pevent_find_common_field(event, "common_lock_depth");
-               if (field)
-                       lock_depth_exists = 1;
-       }
        if (lock_depth_exists)
                lock_depth = parse_common_lock_depth(pevent, data);
+       else if (check_lock_depth) {
+               lock_depth = parse_common_lock_depth(pevent, data);
+               if (lock_depth < 0)
+                       check_lock_depth = 0;
+               else
+                       lock_depth_exists = 1;
+       }
+
+       /* migrate_disable may not always exist */
+       if (migrate_disable_exists)
+               migrate_disable = parse_common_migrate_disable(pevent, data);
+       else if (check_migrate_disable) {
+               migrate_disable = parse_common_migrate_disable(pevent, data);
+               if (migrate_disable < 0)
+                       check_migrate_disable = 0;
+               else
+                       migrate_disable_exists = 1;
+       }
 
        hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
        softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
@@ -3930,6 +4096,13 @@ void pevent_data_lat_fmt(struct pevent *pevent,
        else
                trace_seq_putc(s, '.');
 
+       if (migrate_disable_exists) {
+               if (migrate_disable < 0)
+                       trace_seq_putc(s, '.');
+               else
+                       trace_seq_printf(s, "%d", migrate_disable);
+       }
+
        if (lock_depth_exists) {
                if (lock_depth < 0)
                        trace_seq_putc(s, '.');
@@ -3996,10 +4169,7 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
  * pevent_data_comm_from_pid - parse the data into the print format
  * @s: the trace_seq to write to
  * @event: the handle to the event
- * @cpu: the cpu the event was recorded on
- * @data: the raw data
- * @size: the size of the raw data
- * @nsecs: the timestamp of the event
+ * @record: the record to read from
  *
  * This parses the raw @data using the given @event information and
  * writes the print format into the trace_seq.
@@ -4279,6 +4449,13 @@ static void print_args(struct print_arg *args)
                trace_seq_destroy(&s);
                printf(")");
                break;
+       case PRINT_HEX:
+               printf("__print_hex(");
+               print_args(args->hex.field);
+               printf(", ");
+               print_args(args->hex.size);
+               printf(")");
+               break;
        case PRINT_STRING:
        case PRINT_BSTRING:
                printf("__get_str(%s)", args->string.string);
@@ -4541,6 +4718,8 @@ int pevent_parse_event(struct pevent *pevent,
                die("failed to read event id");
 
        event->system = strdup(sys);
+       if (!event->system)
+               die("failed to allocate system");
 
        /* Add pevent to event so that it can be referenced */
        event->pevent = pevent;
@@ -4582,6 +4761,11 @@ int pevent_parse_event(struct pevent *pevent,
                        list = &arg->next;
                        arg->type = PRINT_FIELD;
                        arg->field.name = strdup(field->name);
+                       if (!arg->field.name) {
+                               do_warning("failed to allocate field name");
+                               event->flags |= EVENT_FL_FAILED;
+                               return -1;
+                       }
                        arg->field.field = field;
                }
                return 0;
@@ -4753,7 +4937,7 @@ int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
  * @record: The record with the field name.
  * @err: print default error if failed.
  *
- * Returns: 0 on success, -1 field not fould, or 1 if buffer is full.
+ * Returns: 0 on success, -1 field not found, or 1 if buffer is full.
  */
 int pevent_print_num_field(struct trace_seq *s, const char *fmt,
                           struct event_format *event, const char *name,
@@ -4795,11 +4979,12 @@ static void free_func_handle(struct pevent_function_handler *func)
  * pevent_register_print_function - register a helper function
  * @pevent: the handle to the pevent
  * @func: the function to process the helper function
+ * @ret_type: the return type of the helper function
  * @name: the name of the helper function
  * @parameters: A list of enum pevent_func_arg_type
  *
  * Some events may have helper functions in the print format arguments.
- * This allows a plugin to dynmically create a way to process one
+ * This allows a plugin to dynamically create a way to process one
  * of these functions.
  *
  * The @parameters is a variable list of pevent_func_arg_type enums that
@@ -4870,12 +5055,13 @@ int pevent_register_print_function(struct pevent *pevent,
 }
 
 /**
- * pevent_register_event_handle - register a way to parse an event
+ * pevent_register_event_handler - register a way to parse an event
  * @pevent: the handle to the pevent
  * @id: the id of the event to register
  * @sys_name: the system name the event belongs to
  * @event_name: the name of the event
  * @func: the function to call to parse the event information
+ * @context: the data to be passed to @func
  *
  * This function allows a developer to override the parsing of
  * a given event. If for some reason the default print format
@@ -4925,6 +5111,11 @@ int pevent_register_event_handler(struct pevent *pevent,
        if (sys_name)
                handle->sys_name = strdup(sys_name);
 
+       if ((event_name && !handle->event_name) ||
+           (sys_name && !handle->sys_name)) {
+               die("Failed to allocate event/sys name");
+       }
+
        handle->func = func;
        handle->next = pevent->handlers;
        pevent->handlers = handle;
index ac997bc7b59252e5fc0fb2cc9b1e9ef12bd15419..5772ad8cb38646fbd5a6375b528ad710ff217b3f 100644 (file)
@@ -226,6 +226,11 @@ struct print_arg_symbol {
        struct print_flag_sym   *symbols;
 };
 
+struct print_arg_hex {
+       struct print_arg        *field;
+       struct print_arg        *size;
+};
+
 struct print_arg_dynarray {
        struct format_field     *field;
        struct print_arg        *index;
@@ -253,6 +258,7 @@ enum print_arg_type {
        PRINT_FIELD,
        PRINT_FLAGS,
        PRINT_SYMBOL,
+       PRINT_HEX,
        PRINT_TYPE,
        PRINT_STRING,
        PRINT_BSTRING,
@@ -270,6 +276,7 @@ struct print_arg {
                struct print_arg_typecast       typecast;
                struct print_arg_flags          flags;
                struct print_arg_symbol         symbol;
+               struct print_arg_hex            hex;
                struct print_arg_func           func;
                struct print_arg_string         string;
                struct print_arg_op             op;
index dfcfe2c131de6e3d8ea6c26cbf452c2834fd90d7..ad17855528f9adaa82cb37b0e6a8fe7ede2ed755 100644 (file)
@@ -96,7 +96,7 @@ static enum event_type read_token(char **tok)
            (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
            pevent_peek_char() == '~') {
                /* append it */
-               *tok = malloc(3);
+               *tok = malloc_or_die(3);
                sprintf(*tok, "%c%c", *token, '~');
                free_token(token);
                /* Now remove the '~' from the buffer */
@@ -148,17 +148,11 @@ add_filter_type(struct event_filter *filter, int id)
        if (filter_type)
                return filter_type;
 
-       if (!filter->filters)
-               filter->event_filters =
-                       malloc_or_die(sizeof(*filter->event_filters));
-       else {
-               filter->event_filters =
-                       realloc(filter->event_filters,
-                               sizeof(*filter->event_filters) *
-                               (filter->filters + 1));
-               if (!filter->event_filters)
-                       die("Could not allocate filter");
-       }
+       filter->event_filters = realloc(filter->event_filters,
+                                       sizeof(*filter->event_filters) *
+                                       (filter->filters + 1));
+       if (!filter->event_filters)
+               die("Could not allocate filter");
 
        for (i = 0; i < filter->filters; i++) {
                if (filter->event_filters[i].event_id > id)
@@ -1480,7 +1474,7 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
 {
        struct filter_type *filter_type;
        int count = 0;
-       int *ids;
+       int *ids = NULL;
        int i;
 
        if (!filter->filters)
@@ -1504,10 +1498,8 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
                default:
                        break;
                }
-               if (count)
-                       ids = realloc(ids, sizeof(*ids) * (count + 1));
-               else
-                       ids = malloc(sizeof(*ids));
+
+               ids = realloc(ids, sizeof(*ids) * (count + 1));
                if (!ids)
                        die("Can't allocate ids");
                ids[count++] = filter_type->event_id;
@@ -1710,18 +1702,43 @@ static int test_num(struct event_format *event,
 
 static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
 {
-       const char *val = record->data + arg->str.field->offset;
+       struct event_format *event;
+       struct pevent *pevent;
+       unsigned long long addr;
+       const char *val = NULL;
+       char hex[64];
 
-       /*
-        * We need to copy the data since we can't be sure the field
-        * is null terminated.
-        */
-       if (*(val + arg->str.field->size - 1)) {
-               /* copy it */
-               memcpy(arg->str.buffer, val, arg->str.field->size);
-               /* the buffer is already NULL terminated */
-               val = arg->str.buffer;
+       /* If the field is not a string convert it */
+       if (arg->str.field->flags & FIELD_IS_STRING) {
+               val = record->data + arg->str.field->offset;
+
+               /*
+                * We need to copy the data since we can't be sure the field
+                * is null terminated.
+                */
+               if (*(val + arg->str.field->size - 1)) {
+                       /* copy it */
+                       memcpy(arg->str.buffer, val, arg->str.field->size);
+                       /* the buffer is already NULL terminated */
+                       val = arg->str.buffer;
+               }
+
+       } else {
+               event = arg->str.field->event;
+               pevent = event->pevent;
+               addr = get_value(event, arg->str.field, record);
+
+               if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG))
+                       /* convert to a kernel symbol */
+                       val = pevent_find_function(pevent, addr);
+
+               if (val == NULL) {
+                       /* just use the hex of the string name */
+                       snprintf(hex, 64, "0x%llx", addr);
+                       val = hex;
+               }
        }
+
        return val;
 }
 
@@ -2001,11 +2018,13 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
        char *lstr;
        char *rstr;
        char *op;
-       char *str;
+       char *str = NULL;
        int len;
 
        lstr = arg_to_str(filter, arg->exp.left);
        rstr = arg_to_str(filter, arg->exp.right);
+       if (!lstr || !rstr)
+               goto out;
 
        switch (arg->exp.type) {
        case FILTER_EXP_ADD:
@@ -2045,6 +2064,7 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
        len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
        str = malloc_or_die(len);
        snprintf(str, len, "%s %s %s", lstr, op, rstr);
+out:
        free(lstr);
        free(rstr);
 
@@ -2061,6 +2081,8 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
 
        lstr = arg_to_str(filter, arg->num.left);
        rstr = arg_to_str(filter, arg->num.right);
+       if (!lstr || !rstr)
+               goto out;
 
        switch (arg->num.type) {
        case FILTER_CMP_EQ:
@@ -2097,6 +2119,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
                break;
        }
 
+out:
        free(lstr);
        free(rstr);
        return str;
@@ -2247,7 +2270,12 @@ int pevent_filter_compare(struct event_filter *filter1, struct event_filter *fil
                /* The best way to compare complex filters is with strings */
                str1 = arg_to_str(filter1, filter_type1->filter);
                str2 = arg_to_str(filter2, filter_type2->filter);
-               result = strcmp(str1, str2) != 0;
+               if (str1 && str2)
+                       result = strcmp(str1, str2) != 0;
+               else
+                       /* bail out if allocation fails */
+                       result = 1;
+
                free(str1);
                free(str2);
                if (result)
index a3dbadb26ef596d29f6e2e9c3a5326bff4dfdad7..7065cd6fbdfc576a28d588f778354d15771a2ad1 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This 'perf bench' command is general framework for benchmark suites.
+This 'perf bench' command is general framework for benchmark suites.
 
 COMMON OPTIONS
 --------------
@@ -45,14 +45,20 @@ SUBSYSTEM
 'sched'::
        Scheduler and IPC mechanisms.
 
+'mem'::
+       Memory access performance.
+
+'all'::
+       All benchmark subsystems.
+
 SUITES FOR 'sched'
 ~~~~~~~~~~~~~~~~~~
 *messaging*::
 Suite for evaluating performance of scheduler and IPC mechanisms.
 Based on hackbench by Rusty Russell.
 
-Options of *pipe*
-^^^^^^^^^^^^^^^^^
+Options of *messaging*
+^^^^^^^^^^^^^^^^^^^^^^
 -p::
 --pipe::
 Use pipe() instead of socketpair()
@@ -115,6 +121,72 @@ Example of *pipe*
                 59004 ops/sec
 ---------------------
 
+SUITES FOR 'mem'
+~~~~~~~~~~~~~~~~
+*memcpy*::
+Suite for evaluating performance of simple memory copy in various ways.
+
+Options of *memcpy*
+^^^^^^^^^^^^^^^^^^^
+-l::
+--length::
+Specify length of memory to copy (default: 1MB).
+Available units are B, KB, MB, GB and TB (case insensitive).
+
+-r::
+--routine::
+Specify routine to copy (default: default).
+Available routines are depend on the architecture.
+On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported.
+
+-i::
+--iterations::
+Repeat memcpy invocation this number of times.
+
+-c::
+--cycle::
+Use perf's cpu-cycles event instead of gettimeofday syscall.
+
+-o::
+--only-prefault::
+Show only the result with page faults before memcpy.
+
+-n::
+--no-prefault::
+Show only the result without page faults before memcpy.
+
+*memset*::
+Suite for evaluating performance of simple memory set in various ways.
+
+Options of *memset*
+^^^^^^^^^^^^^^^^^^^
+-l::
+--length::
+Specify length of memory to set (default: 1MB).
+Available units are B, KB, MB, GB and TB (case insensitive).
+
+-r::
+--routine::
+Specify routine to set (default: default).
+Available routines are depend on the architecture.
+On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported.
+
+-i::
+--iterations::
+Repeat memset invocation this number of times.
+
+-c::
+--cycle::
+Use perf's cpu-cycles event instead of gettimeofday syscall.
+
+-o::
+--only-prefault::
+Show only the result with page faults before memset.
+
+-n::
+--no-prefault::
+Show only the result without page faults before memset.
+
 SEE ALSO
 --------
 linkperf:perf[1]
index 2d89f02719b5f6ce52e502414c031a2d7610ca9a..495210a612c4d218170f696dcf5d93323f22a571 100644 (file)
@@ -57,7 +57,7 @@ OPTIONS
 
 -s::
 --sort=::
-       Sort by key(s): pid, comm, dso, symbol, parent.
+       Sort by key(s): pid, comm, dso, symbol, parent, srcline.
 
 -p::
 --parent=<regex>::
index 4a5680cb242ebe656c266c19bcf81bc64bbc623c..5b80d84d6b4a3e7e430499d0381c11a8856f316d 100644 (file)
@@ -112,7 +112,7 @@ Default is to monitor all CPUS.
 
 -s::
 --sort::
-       Sort by key(s): pid, comm, dso, symbol, parent
+       Sort by key(s): pid, comm, dso, symbol, parent, srcline.
 
 -n::
 --show-nr-samples::
index 0eee64cfe9a0f48ced0ee2397068979763355cd4..75d74e5db8d552372aa0b7c19861c76458784f5e 100644 (file)
@@ -155,7 +155,7 @@ endif
 
 ### --- END CONFIGURATION SECTION ---
 
-BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 BASIC_LDFLAGS =
 
 # Guard against environment variables
@@ -503,6 +503,7 @@ else
                LIB_OBJS += $(OUTPUT)ui/progress.o
                LIB_OBJS += $(OUTPUT)ui/util.o
                LIB_OBJS += $(OUTPUT)ui/tui/setup.o
+               LIB_OBJS += $(OUTPUT)ui/tui/util.o
                LIB_H += ui/browser.h
                LIB_H += ui/browsers/map.h
                LIB_H += ui/helpline.h
@@ -522,13 +523,18 @@ else
                msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
                BASIC_CFLAGS += -DNO_GTK2_SUPPORT
        else
+               ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y)
+                       BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
+               endif
                BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
                EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
                LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
                LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
+               LIB_OBJS += $(OUTPUT)ui/gtk/util.o
                # Make sure that it'd be included only once.
                ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
                        LIB_OBJS += $(OUTPUT)ui/setup.o
+                       LIB_OBJS += $(OUTPUT)ui/util.o
                endif
        endif
 endif
index 71557225bf92aeb708100acfa3f5027948de3831..02dad5d3359b0f23abe24169a126b2dc3bacfd99 100644 (file)
 static const char      *length_str     = "1MB";
 static const char      *routine        = "default";
 static int             iterations      = 1;
-static bool            use_clock;
-static int             clock_fd;
+static bool            use_cycle;
+static int             cycle_fd;
 static bool            only_prefault;
 static bool            no_prefault;
 
 static const struct option options[] = {
        OPT_STRING('l', "length", &length_str, "1MB",
                    "Specify length of memory to copy. "
-                   "available unit: B, MB, GB (upper and lower)"),
+                   "Available units: B, KB, MB, GB and TB (upper and lower)"),
        OPT_STRING('r', "routine", &routine, "default",
                    "Specify routine to copy"),
        OPT_INTEGER('i', "iterations", &iterations,
                    "repeat memcpy() invocation this number of times"),
-       OPT_BOOLEAN('c', "clock", &use_clock,
-                   "Use CPU clock for measuring"),
+       OPT_BOOLEAN('c', "cycle", &use_cycle,
+                   "Use cycles event instead of gettimeofday() for measuring"),
        OPT_BOOLEAN('o', "only-prefault", &only_prefault,
                    "Show only the result with page faults before memcpy()"),
        OPT_BOOLEAN('n', "no-prefault", &no_prefault,
@@ -76,27 +76,27 @@ static const char * const bench_mem_memcpy_usage[] = {
        NULL
 };
 
-static struct perf_event_attr clock_attr = {
+static struct perf_event_attr cycle_attr = {
        .type           = PERF_TYPE_HARDWARE,
        .config         = PERF_COUNT_HW_CPU_CYCLES
 };
 
-static void init_clock(void)
+static void init_cycle(void)
 {
-       clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
+       cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0);
 
-       if (clock_fd < 0 && errno == ENOSYS)
+       if (cycle_fd < 0 && errno == ENOSYS)
                die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
        else
-               BUG_ON(clock_fd < 0);
+               BUG_ON(cycle_fd < 0);
 }
 
-static u64 get_clock(void)
+static u64 get_cycle(void)
 {
        int ret;
        u64 clk;
 
-       ret = read(clock_fd, &clk, sizeof(u64));
+       ret = read(cycle_fd, &clk, sizeof(u64));
        BUG_ON(ret != sizeof(u64));
 
        return clk;
@@ -119,9 +119,9 @@ static void alloc_mem(void **dst, void **src, size_t length)
                die("memory allocation failed - maybe length is too large?\n");
 }
 
-static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
+static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault)
 {
-       u64 clock_start = 0ULL, clock_end = 0ULL;
+       u64 cycle_start = 0ULL, cycle_end = 0ULL;
        void *src = NULL, *dst = NULL;
        int i;
 
@@ -130,14 +130,14 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
        if (prefault)
                fn(dst, src, len);
 
-       clock_start = get_clock();
+       cycle_start = get_cycle();
        for (i = 0; i < iterations; ++i)
                fn(dst, src, len);
-       clock_end = get_clock();
+       cycle_end = get_cycle();
 
        free(src);
        free(dst);
-       return clock_end - clock_start;
+       return cycle_end - cycle_start;
 }
 
 static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
@@ -182,17 +182,17 @@ int bench_mem_memcpy(int argc, const char **argv,
        int i;
        size_t len;
        double result_bps[2];
-       u64 result_clock[2];
+       u64 result_cycle[2];
 
        argc = parse_options(argc, argv, options,
                             bench_mem_memcpy_usage, 0);
 
-       if (use_clock)
-               init_clock();
+       if (use_cycle)
+               init_cycle();
 
        len = (size_t)perf_atoll((char *)length_str);
 
-       result_clock[0] = result_clock[1] = 0ULL;
+       result_cycle[0] = result_cycle[1] = 0ULL;
        result_bps[0] = result_bps[1] = 0.0;
 
        if ((s64)len <= 0) {
@@ -223,11 +223,11 @@ int bench_mem_memcpy(int argc, const char **argv,
 
        if (!only_prefault && !no_prefault) {
                /* show both of results */
-               if (use_clock) {
-                       result_clock[0] =
-                               do_memcpy_clock(routines[i].fn, len, false);
-                       result_clock[1] =
-                               do_memcpy_clock(routines[i].fn, len, true);
+               if (use_cycle) {
+                       result_cycle[0] =
+                               do_memcpy_cycle(routines[i].fn, len, false);
+                       result_cycle[1] =
+                               do_memcpy_cycle(routines[i].fn, len, true);
                } else {
                        result_bps[0] =
                                do_memcpy_gettimeofday(routines[i].fn,
@@ -237,9 +237,9 @@ int bench_mem_memcpy(int argc, const char **argv,
                                                len, true);
                }
        } else {
-               if (use_clock) {
-                       result_clock[pf] =
-                               do_memcpy_clock(routines[i].fn,
+               if (use_cycle) {
+                       result_cycle[pf] =
+                               do_memcpy_cycle(routines[i].fn,
                                                len, only_prefault);
                } else {
                        result_bps[pf] =
@@ -251,12 +251,12 @@ int bench_mem_memcpy(int argc, const char **argv,
        switch (bench_format) {
        case BENCH_FORMAT_DEFAULT:
                if (!only_prefault && !no_prefault) {
-                       if (use_clock) {
-                               printf(" %14lf Clock/Byte\n",
-                                       (double)result_clock[0]
+                       if (use_cycle) {
+                               printf(" %14lf Cycle/Byte\n",
+                                       (double)result_cycle[0]
                                        / (double)len);
-                               printf(" %14lf Clock/Byte (with prefault)\n",
-                                       (double)result_clock[1]
+                               printf(" %14lf Cycle/Byte (with prefault)\n",
+                                       (double)result_cycle[1]
                                        / (double)len);
                        } else {
                                print_bps(result_bps[0]);
@@ -265,9 +265,9 @@ int bench_mem_memcpy(int argc, const char **argv,
                                printf(" (with prefault)\n");
                        }
                } else {
-                       if (use_clock) {
-                               printf(" %14lf Clock/Byte",
-                                       (double)result_clock[pf]
+                       if (use_cycle) {
+                               printf(" %14lf Cycle/Byte",
+                                       (double)result_cycle[pf]
                                        / (double)len);
                        } else
                                print_bps(result_bps[pf]);
@@ -277,17 +277,17 @@ int bench_mem_memcpy(int argc, const char **argv,
                break;
        case BENCH_FORMAT_SIMPLE:
                if (!only_prefault && !no_prefault) {
-                       if (use_clock) {
+                       if (use_cycle) {
                                printf("%lf %lf\n",
-                                       (double)result_clock[0] / (double)len,
-                                       (double)result_clock[1] / (double)len);
+                                       (double)result_cycle[0] / (double)len,
+                                       (double)result_cycle[1] / (double)len);
                        } else {
                                printf("%lf %lf\n",
                                        result_bps[0], result_bps[1]);
                        }
                } else {
-                       if (use_clock) {
-                               printf("%lf\n", (double)result_clock[pf]
+                       if (use_cycle) {
+                               printf("%lf\n", (double)result_cycle[pf]
                                        / (double)len);
                        } else
                                printf("%lf\n", result_bps[pf]);
index e9079185bd72d32e48dfee280ead72c96c7d9ef3..350cc9557265197a03e35abb3fd49dc39dde64ac 100644 (file)
 static const char      *length_str     = "1MB";
 static const char      *routine        = "default";
 static int             iterations      = 1;
-static bool            use_clock;
-static int             clock_fd;
+static bool            use_cycle;
+static int             cycle_fd;
 static bool            only_prefault;
 static bool            no_prefault;
 
 static const struct option options[] = {
        OPT_STRING('l', "length", &length_str, "1MB",
-                   "Specify length of memory to copy. "
-                   "available unit: B, MB, GB (upper and lower)"),
+                   "Specify length of memory to set. "
+                   "Available units: B, KB, MB, GB and TB (upper and lower)"),
        OPT_STRING('r', "routine", &routine, "default",
-                   "Specify routine to copy"),
+                   "Specify routine to set"),
        OPT_INTEGER('i', "iterations", &iterations,
                    "repeat memset() invocation this number of times"),
-       OPT_BOOLEAN('c', "clock", &use_clock,
-                   "Use CPU clock for measuring"),
+       OPT_BOOLEAN('c', "cycle", &use_cycle,
+                   "Use cycles event instead of gettimeofday() for measuring"),
        OPT_BOOLEAN('o', "only-prefault", &only_prefault,
                    "Show only the result with page faults before memset()"),
        OPT_BOOLEAN('n', "no-prefault", &no_prefault,
@@ -76,27 +76,27 @@ static const char * const bench_mem_memset_usage[] = {
        NULL
 };
 
-static struct perf_event_attr clock_attr = {
+static struct perf_event_attr cycle_attr = {
        .type           = PERF_TYPE_HARDWARE,
        .config         = PERF_COUNT_HW_CPU_CYCLES
 };
 
-static void init_clock(void)
+static void init_cycle(void)
 {
-       clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
+       cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0);
 
-       if (clock_fd < 0 && errno == ENOSYS)
+       if (cycle_fd < 0 && errno == ENOSYS)
                die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
        else
-               BUG_ON(clock_fd < 0);
+               BUG_ON(cycle_fd < 0);
 }
 
-static u64 get_clock(void)
+static u64 get_cycle(void)
 {
        int ret;
        u64 clk;
 
-       ret = read(clock_fd, &clk, sizeof(u64));
+       ret = read(cycle_fd, &clk, sizeof(u64));
        BUG_ON(ret != sizeof(u64));
 
        return clk;
@@ -115,9 +115,9 @@ static void alloc_mem(void **dst, size_t length)
                die("memory allocation failed - maybe length is too large?\n");
 }
 
-static u64 do_memset_clock(memset_t fn, size_t len, bool prefault)
+static u64 do_memset_cycle(memset_t fn, size_t len, bool prefault)
 {
-       u64 clock_start = 0ULL, clock_end = 0ULL;
+       u64 cycle_start = 0ULL, cycle_end = 0ULL;
        void *dst = NULL;
        int i;
 
@@ -126,13 +126,13 @@ static u64 do_memset_clock(memset_t fn, size_t len, bool prefault)
        if (prefault)
                fn(dst, -1, len);
 
-       clock_start = get_clock();
+       cycle_start = get_cycle();
        for (i = 0; i < iterations; ++i)
                fn(dst, i, len);
-       clock_end = get_clock();
+       cycle_end = get_cycle();
 
        free(dst);
-       return clock_end - clock_start;
+       return cycle_end - cycle_start;
 }
 
 static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault)
@@ -176,17 +176,17 @@ int bench_mem_memset(int argc, const char **argv,
        int i;
        size_t len;
        double result_bps[2];
-       u64 result_clock[2];
+       u64 result_cycle[2];
 
        argc = parse_options(argc, argv, options,
                             bench_mem_memset_usage, 0);
 
-       if (use_clock)
-               init_clock();
+       if (use_cycle)
+               init_cycle();
 
        len = (size_t)perf_atoll((char *)length_str);
 
-       result_clock[0] = result_clock[1] = 0ULL;
+       result_cycle[0] = result_cycle[1] = 0ULL;
        result_bps[0] = result_bps[1] = 0.0;
 
        if ((s64)len <= 0) {
@@ -217,11 +217,11 @@ int bench_mem_memset(int argc, const char **argv,
 
        if (!only_prefault && !no_prefault) {
                /* show both of results */
-               if (use_clock) {
-                       result_clock[0] =
-                               do_memset_clock(routines[i].fn, len, false);
-                       result_clock[1] =
-                               do_memset_clock(routines[i].fn, len, true);
+               if (use_cycle) {
+                       result_cycle[0] =
+                               do_memset_cycle(routines[i].fn, len, false);
+                       result_cycle[1] =
+                               do_memset_cycle(routines[i].fn, len, true);
                } else {
                        result_bps[0] =
                                do_memset_gettimeofday(routines[i].fn,
@@ -231,9 +231,9 @@ int bench_mem_memset(int argc, const char **argv,
                                                len, true);
                }
        } else {
-               if (use_clock) {
-                       result_clock[pf] =
-                               do_memset_clock(routines[i].fn,
+               if (use_cycle) {
+                       result_cycle[pf] =
+                               do_memset_cycle(routines[i].fn,
                                                len, only_prefault);
                } else {
                        result_bps[pf] =
@@ -245,12 +245,12 @@ int bench_mem_memset(int argc, const char **argv,
        switch (bench_format) {
        case BENCH_FORMAT_DEFAULT:
                if (!only_prefault && !no_prefault) {
-                       if (use_clock) {
-                               printf(" %14lf Clock/Byte\n",
-                                       (double)result_clock[0]
+                       if (use_cycle) {
+                               printf(" %14lf Cycle/Byte\n",
+                                       (double)result_cycle[0]
                                        / (double)len);
-                               printf(" %14lf Clock/Byte (with prefault)\n ",
-                                       (double)result_clock[1]
+                               printf(" %14lf Cycle/Byte (with prefault)\n ",
+                                       (double)result_cycle[1]
                                        / (double)len);
                        } else {
                                print_bps(result_bps[0]);
@@ -259,9 +259,9 @@ int bench_mem_memset(int argc, const char **argv,
                                printf(" (with prefault)\n");
                        }
                } else {
-                       if (use_clock) {
-                               printf(" %14lf Clock/Byte",
-                                       (double)result_clock[pf]
+                       if (use_cycle) {
+                               printf(" %14lf Cycle/Byte",
+                                       (double)result_cycle[pf]
                                        / (double)len);
                        } else
                                print_bps(result_bps[pf]);
@@ -271,17 +271,17 @@ int bench_mem_memset(int argc, const char **argv,
                break;
        case BENCH_FORMAT_SIMPLE:
                if (!only_prefault && !no_prefault) {
-                       if (use_clock) {
+                       if (use_cycle) {
                                printf("%lf %lf\n",
-                                       (double)result_clock[0] / (double)len,
-                                       (double)result_clock[1] / (double)len);
+                                       (double)result_cycle[0] / (double)len,
+                                       (double)result_cycle[1] / (double)len);
                        } else {
                                printf("%lf %lf\n",
                                        result_bps[0], result_bps[1]);
                        }
                } else {
-                       if (use_clock) {
-                               printf("%lf\n", (double)result_clock[pf]
+                       if (use_cycle) {
+                               printf("%lf\n", (double)result_cycle[pf]
                                        / (double)len);
                        } else
                                printf("%lf\n", result_bps[pf]);
index b0e74ab2d7a2990d8d1fce67b95a555d53a70ee3..1f3100216448da9d0d794847a0c0f0b315bd59fb 100644 (file)
@@ -33,7 +33,7 @@ struct bench_suite {
 };
                                                \
 /* sentinel: easy for help */
-#define suite_all { "all", "test all suite (pseudo suite)", NULL }
+#define suite_all { "all", "Test all benchmark suites", NULL }
 
 static struct bench_suite sched_suites[] = {
        { "messaging",
@@ -75,7 +75,7 @@ static struct bench_subsys subsystems[] = {
          "memory access performance",
          mem_suites },
        { "all",                /* sentinel: easy for help */
-         "test all subsystem (pseudo subsystem)",
+         "all benchmark subsystem",
          NULL },
        { NULL,
          NULL,
index acd78dc283411692f9e7e48b78085d9b5da63471..0dd5a058f766e2e2b2ad7196af78bf3d7a81d563 100644 (file)
@@ -60,7 +60,7 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail
        list_for_each_entry(pos, &session->evlist->entries, node) {
                bool first = true;
 
-               printf("%s", event_name(pos));
+               printf("%s", perf_evsel__name(pos));
 
                if (details->verbose || details->freq) {
                        comma_printf(&first, " sample_freq=%" PRIu64,
index 547af48deb4f99081221f566f48dc023ab6b0e76..ce35015f2dc6423901f7d42b223754b4b67117e3 100644 (file)
@@ -57,6 +57,11 @@ static unsigned long nr_allocs, nr_cross_allocs;
 
 #define PATH_SYS_NODE  "/sys/devices/system/node"
 
+struct perf_kmem {
+       struct perf_tool    tool;
+       struct perf_session *session;
+};
+
 static void init_cpunode_map(void)
 {
        FILE *fp;
@@ -278,14 +283,16 @@ static void process_free_event(void *data,
        s_alloc->alloc_cpu = -1;
 }
 
-static void process_raw_event(union perf_event *raw_event __used, void *data,
+static void process_raw_event(struct perf_tool *tool,
+                             union perf_event *raw_event __used, void *data,
                              int cpu, u64 timestamp, struct thread *thread)
 {
+       struct perf_kmem *kmem = container_of(tool, struct perf_kmem, tool);
        struct event_format *event;
        int type;
 
-       type = trace_parse_common_type(data);
-       event = trace_find_event(type);
+       type = trace_parse_common_type(kmem->session->pevent, data);
+       event = pevent_find_event(kmem->session->pevent, type);
 
        if (!strcmp(event->name, "kmalloc") ||
            !strcmp(event->name, "kmem_cache_alloc")) {
@@ -306,7 +313,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
        }
 }
 
-static int process_sample_event(struct perf_tool *tool __used,
+static int process_sample_event(struct perf_tool *tool,
                                union perf_event *event,
                                struct perf_sample *sample,
                                struct perf_evsel *evsel __used,
@@ -322,16 +329,18 @@ static int process_sample_event(struct perf_tool *tool __used,
 
        dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
 
-       process_raw_event(event, sample->raw_data, sample->cpu,
+       process_raw_event(tool, event, sample->raw_data, sample->cpu,
                          sample->time, thread);
 
        return 0;
 }
 
-static struct perf_tool perf_kmem = {
-       .sample                 = process_sample_event,
-       .comm                   = perf_event__process_comm,
-       .ordered_samples        = true,
+static struct perf_kmem perf_kmem = {
+       .tool = {
+               .sample                 = process_sample_event,
+               .comm                   = perf_event__process_comm,
+               .ordered_samples        = true,
+       },
 };
 
 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -486,11 +495,15 @@ static void sort_result(void)
 static int __cmd_kmem(void)
 {
        int err = -EINVAL;
-       struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-                                                        0, false, &perf_kmem);
+       struct perf_session *session;
+
+       session = perf_session__new(input_name, O_RDONLY, 0, false,
+                                   &perf_kmem.tool);
        if (session == NULL)
                return -ENOMEM;
 
+       perf_kmem.session = session;
+
        if (perf_session__create_kernel_maps(session) < 0)
                goto out_delete;
 
@@ -498,7 +511,7 @@ static int __cmd_kmem(void)
                goto out_delete;
 
        setup_pager();
-       err = perf_session__process_events(session, &perf_kmem);
+       err = perf_session__process_events(session, &perf_kmem.tool);
        if (err != 0)
                goto out_delete;
        sort_result();
index fd53319de20d68f906536787c48523769e565aba..b3c4285488688ba19b6073bd6c743a84e4e0e8b1 100644 (file)
@@ -724,8 +724,8 @@ process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
        struct event_format *event;
        int type;
 
-       type = trace_parse_common_type(data);
-       event = trace_find_event(type);
+       type = trace_parse_common_type(session->pevent, data);
+       event = pevent_find_event(session->pevent, type);
 
        if (!strcmp(event->name, "lock_acquire"))
                process_lock_acquire_event(data, event, cpu, timestamp, thread);
index f95840d04e4c7a224821e395600df2bbdc7e4323..f5a6452931e6dabaa4f3b4593ab91f30aa7d586b 100644 (file)
@@ -265,7 +265,7 @@ try_again:
 
                        if (err == ENOENT) {
                                ui__error("The %s event is not supported.\n",
-                                           event_name(pos));
+                                         perf_evsel__name(pos));
                                exit(EXIT_FAILURE);
                        }
 
@@ -916,7 +916,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
                usage_with_options(record_usage, record_options);
 
        list_for_each_entry(pos, &evsel_list->entries, node) {
-               if (perf_header__push_event(pos->attr.config, event_name(pos)))
+               if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
                        goto out_free_fd;
        }
 
index 25249f76329daf851f925240f8c295c0c3fc5bdc..69b1c1185159174f070425d15c17afc8d5325f50 100644 (file)
@@ -69,7 +69,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
 
        if ((sort__has_parent || symbol_conf.use_callchain)
            && sample->callchain) {
-               err = machine__resolve_callchain(machine, evsel, al->thread,
+               err = machine__resolve_callchain(machine, al->thread,
                                                 sample->callchain, &parent);
                if (err)
                        return err;
@@ -140,7 +140,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
        struct hist_entry *he;
 
        if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
-               err = machine__resolve_callchain(machine, evsel, al->thread,
+               err = machine__resolve_callchain(machine, al->thread,
                                                 sample->callchain, &parent);
                if (err)
                        return err;
@@ -230,7 +230,7 @@ static int process_read_event(struct perf_tool *tool,
        struct perf_report *rep = container_of(tool, struct perf_report, tool);
 
        if (rep->show_threads) {
-               const char *name = evsel ? event_name(evsel) : "unknown";
+               const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
                perf_read_values_add_value(&rep->show_threads_values,
                                           event->read.pid, event->read.tid,
                                           event->read.id,
@@ -239,17 +239,18 @@ static int process_read_event(struct perf_tool *tool,
        }
 
        dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
-                   evsel ? event_name(evsel) : "FAIL",
+                   evsel ? perf_evsel__name(evsel) : "FAIL",
                    event->read.value);
 
        return 0;
 }
 
+/* For pipe mode, sample_type is not currently set */
 static int perf_report__setup_sample_type(struct perf_report *rep)
 {
        struct perf_session *self = rep->session;
 
-       if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
+       if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
                        ui__error("Selected --sort parent, but no "
                                    "callchain data. Did you call "
@@ -272,7 +273,8 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
        }
 
        if (sort__branch_mode == 1) {
-               if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
+               if (!self->fd_pipe &&
+                   !(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
                        ui__error("Selected -b but no branch data. "
                                  "Did you call perf record without -b?\n");
                        return -1;
@@ -314,7 +316,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
 
        list_for_each_entry(pos, &evlist->entries, node) {
                struct hists *hists = &pos->hists;
-               const char *evname = event_name(pos);
+               const char *evname = perf_evsel__name(pos);
 
                hists__fprintf_nr_sample_events(hists, evname, stdout);
                hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
index b125e07eb39937e314b314943ad4061ba467a98c..7a9ad2b1ee7601de26ed2d97ff91fae39a46f185 100644 (file)
@@ -43,6 +43,11 @@ static u64                   sleep_measurement_overhead;
 
 static unsigned long           nr_tasks;
 
+struct perf_sched {
+       struct perf_tool    tool;
+       struct perf_session *session;
+};
+
 struct sched_atom;
 
 struct task_desc {
@@ -1597,11 +1602,13 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
                                                 struct perf_evsel *evsel,
                                                 struct machine *machine)
 {
+       struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
+       struct pevent *pevent = sched->session->pevent;
        struct thread *thread = machine__findnew_thread(machine, sample->pid);
 
        if (thread == NULL) {
                pr_debug("problem processing %s event, skipping it.\n",
-                        evsel->name);
+                        perf_evsel__name(evsel));
                return -1;
        }
 
@@ -1612,7 +1619,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
                tracepoint_handler f = evsel->handler.func;
 
                if (evsel->handler.data == NULL)
-                       evsel->handler.data = trace_find_event(evsel->attr.config);
+                       evsel->handler.data = pevent_find_event(pevent,
+                                                         evsel->attr.config);
 
                f(tool, evsel->handler.data, sample, machine, thread);
        }
@@ -1620,12 +1628,14 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
        return 0;
 }
 
-static struct perf_tool perf_sched = {
-       .sample                 = perf_sched__process_tracepoint_sample,
-       .comm                   = perf_event__process_comm,
-       .lost                   = perf_event__process_lost,
-       .fork                   = perf_event__process_task,
-       .ordered_samples        = true,
+static struct perf_sched perf_sched = {
+       .tool = {
+               .sample          = perf_sched__process_tracepoint_sample,
+               .comm            = perf_event__process_comm,
+               .lost            = perf_event__process_lost,
+               .fork            = perf_event__process_task,
+               .ordered_samples = true,
+       },
 };
 
 static void read_events(bool destroy, struct perf_session **psession)
@@ -1640,16 +1650,20 @@ static void read_events(bool destroy, struct perf_session **psession)
                { "sched:sched_process_exit", process_sched_exit_event, },
                { "sched:sched_migrate_task", process_sched_migrate_task_event, },
        };
-       struct perf_session *session = perf_session__new(input_name, O_RDONLY,
-                                                        0, false, &perf_sched);
+       struct perf_session *session;
+
+       session = perf_session__new(input_name, O_RDONLY, 0, false,
+                                   &perf_sched.tool);
        if (session == NULL)
                die("No Memory");
 
-       err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers);
+       perf_sched.session = session;
+
+       err = perf_session__set_tracepoints_handlers(session, handlers);
        assert(err == 0);
 
        if (perf_session__has_traces(session, "record -R")) {
-               err = perf_session__process_events(session, &perf_sched);
+               err = perf_session__process_events(session, &perf_sched.tool);
                if (err)
                        die("Failed to process events, error %d", err);
 
index 8e395a538eb92b212ee20ac9e475c7ab70f2f191..1e60ab70b2b14789b17a2a7199f5a8d175709242 100644 (file)
@@ -28,6 +28,11 @@ static bool                  system_wide;
 static const char              *cpu_list;
 static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 
+struct perf_script {
+       struct perf_tool    tool;
+       struct perf_session *session;
+};
+
 enum perf_output_field {
        PERF_OUTPUT_COMM            = 1U << 0,
        PERF_OUTPUT_TID             = 1U << 1,
@@ -137,10 +142,11 @@ static const char *output_field2str(enum perf_output_field field)
 
 #define PRINT_FIELD(x)  (output[attr->type].fields & PERF_OUTPUT_##x)
 
-static int perf_event_attr__check_stype(struct perf_event_attr *attr,
-                                 u64 sample_type, const char *sample_msg,
-                                 enum perf_output_field field)
+static int perf_evsel__check_stype(struct perf_evsel *evsel,
+                                  u64 sample_type, const char *sample_msg,
+                                  enum perf_output_field field)
 {
+       struct perf_event_attr *attr = &evsel->attr;
        int type = attr->type;
        const char *evname;
 
@@ -148,7 +154,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
                return 0;
 
        if (output[type].user_set) {
-               evname = __event_name(attr->type, attr->config);
+               evname = perf_evsel__name(evsel);
                pr_err("Samples for '%s' event do not have %s attribute set. "
                       "Cannot print '%s' field.\n",
                       evname, sample_msg, output_field2str(field));
@@ -157,7 +163,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr,
 
        /* user did not ask for it explicitly so remove from the default list */
        output[type].fields &= ~field;
-       evname = __event_name(attr->type, attr->config);
+       evname = perf_evsel__name(evsel);
        pr_debug("Samples for '%s' event do not have %s attribute set. "
                 "Skipping '%s' field.\n",
                 evname, sample_msg, output_field2str(field));
@@ -175,8 +181,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
                return -EINVAL;
 
        if (PRINT_FIELD(IP)) {
-               if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
-                                          PERF_OUTPUT_IP))
+               if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
+                                           PERF_OUTPUT_IP))
                        return -EINVAL;
 
                if (!no_callchain &&
@@ -185,8 +191,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
        }
 
        if (PRINT_FIELD(ADDR) &&
-               perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
-                                      PERF_OUTPUT_ADDR))
+               perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",
+                                       PERF_OUTPUT_ADDR))
                return -EINVAL;
 
        if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
@@ -208,18 +214,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
        }
 
        if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
-               perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
-                                      PERF_OUTPUT_TID|PERF_OUTPUT_PID))
+               perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
+                                       PERF_OUTPUT_TID|PERF_OUTPUT_PID))
                return -EINVAL;
 
        if (PRINT_FIELD(TIME) &&
-               perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME",
-                                      PERF_OUTPUT_TIME))
+               perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME",
+                                       PERF_OUTPUT_TIME))
                return -EINVAL;
 
        if (PRINT_FIELD(CPU) &&
-               perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU",
-                                      PERF_OUTPUT_CPU))
+               perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU",
+                                       PERF_OUTPUT_CPU))
                return -EINVAL;
 
        return 0;
@@ -256,11 +262,13 @@ static int perf_session__check_output_opt(struct perf_session *session)
        return 0;
 }
 
-static void print_sample_start(struct perf_sample *sample,
+static void print_sample_start(struct pevent *pevent,
+                              struct perf_sample *sample,
                               struct thread *thread,
-                              struct perf_event_attr *attr)
+                              struct perf_evsel *evsel)
 {
        int type;
+       struct perf_event_attr *attr = &evsel->attr;
        struct event_format *event;
        const char *evname = NULL;
        unsigned long secs;
@@ -300,12 +308,18 @@ static void print_sample_start(struct perf_sample *sample,
 
        if (PRINT_FIELD(EVNAME)) {
                if (attr->type == PERF_TYPE_TRACEPOINT) {
-                       type = trace_parse_common_type(sample->raw_data);
-                       event = trace_find_event(type);
+                       /*
+                        * XXX Do we really need this here?
+                        * perf_evlist__set_tracepoint_names should have done
+                        * this already
+                        */
+                       type = trace_parse_common_type(pevent,
+                                                      sample->raw_data);
+                       event = pevent_find_event(pevent, type);
                        if (event)
                                evname = event->name;
                } else
-                       evname = __event_name(attr->type, attr->config);
+                       evname = perf_evsel__name(evsel);
 
                printf("%s: ", evname ? evname : "[unknown]");
        }
@@ -387,7 +401,7 @@ static void print_sample_bts(union perf_event *event,
                        printf(" ");
                else
                        printf("\n");
-               perf_event__print_ip(event, sample, machine, evsel,
+               perf_event__print_ip(event, sample, machine,
                                     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
                                     PRINT_FIELD(SYMOFFSET));
        }
@@ -402,6 +416,7 @@ static void print_sample_bts(union perf_event *event,
 }
 
 static void process_event(union perf_event *event __unused,
+                         struct pevent *pevent,
                          struct perf_sample *sample,
                          struct perf_evsel *evsel,
                          struct machine *machine,
@@ -412,7 +427,7 @@ static void process_event(union perf_event *event __unused,
        if (output[attr->type].fields == 0)
                return;
 
-       print_sample_start(sample, thread, attr);
+       print_sample_start(pevent, sample, thread, evsel);
 
        if (is_bts_event(attr)) {
                print_sample_bts(event, sample, evsel, machine, thread);
@@ -420,7 +435,7 @@ static void process_event(union perf_event *event __unused,
        }
 
        if (PRINT_FIELD(TRACE))
-               print_trace_event(sample->cpu, sample->raw_data,
+               print_trace_event(pevent, sample->cpu, sample->raw_data,
                                  sample->raw_size);
 
        if (PRINT_FIELD(ADDR))
@@ -431,7 +446,7 @@ static void process_event(union perf_event *event __unused,
                        printf(" ");
                else
                        printf("\n");
-               perf_event__print_ip(event, sample, machine, evsel,
+               perf_event__print_ip(event, sample, machine,
                                     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
                                     PRINT_FIELD(SYMOFFSET));
        }
@@ -451,7 +466,8 @@ static int default_stop_script(void)
        return 0;
 }
 
-static int default_generate_script(const char *outfile __unused)
+static int default_generate_script(struct pevent *pevent __unused,
+                                  const char *outfile __unused)
 {
        return 0;
 }
@@ -489,6 +505,7 @@ static int process_sample_event(struct perf_tool *tool __used,
                                struct machine *machine)
 {
        struct addr_location al;
+       struct perf_script *scr = container_of(tool, struct perf_script, tool);
        struct thread *thread = machine__findnew_thread(machine, event->ip.tid);
 
        if (thread == NULL) {
@@ -520,24 +537,27 @@ static int process_sample_event(struct perf_tool *tool __used,
        if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
                return 0;
 
-       scripting_ops->process_event(event, sample, evsel, machine, thread);
+       scripting_ops->process_event(event, scr->session->pevent,
+                                    sample, evsel, machine, thread);
 
        evsel->hists.stats.total_period += sample->period;
        return 0;
 }
 
-static struct perf_tool perf_script = {
-       .sample          = process_sample_event,
-       .mmap            = perf_event__process_mmap,
-       .comm            = perf_event__process_comm,
-       .exit            = perf_event__process_task,
-       .fork            = perf_event__process_task,
-       .attr            = perf_event__process_attr,
-       .event_type      = perf_event__process_event_type,
-       .tracing_data    = perf_event__process_tracing_data,
-       .build_id        = perf_event__process_build_id,
-       .ordered_samples = true,
-       .ordering_requires_timestamps = true,
+static struct perf_script perf_script = {
+       .tool = {
+               .sample          = process_sample_event,
+               .mmap            = perf_event__process_mmap,
+               .comm            = perf_event__process_comm,
+               .exit            = perf_event__process_task,
+               .fork            = perf_event__process_task,
+               .attr            = perf_event__process_attr,
+               .event_type      = perf_event__process_event_type,
+               .tracing_data    = perf_event__process_tracing_data,
+               .build_id        = perf_event__process_build_id,
+               .ordered_samples = true,
+               .ordering_requires_timestamps = true,
+       },
 };
 
 extern volatile int session_done;
@@ -553,7 +573,7 @@ static int __cmd_script(struct perf_session *session)
 
        signal(SIGINT, sig_handler);
 
-       ret = perf_session__process_events(session, &perf_script);
+       ret = perf_session__process_events(session, &perf_script.tool);
 
        if (debug_mode)
                pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@@ -1335,10 +1355,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
        if (!script_name)
                setup_pager();
 
-       session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script);
+       session = perf_session__new(input_name, O_RDONLY, 0, false,
+                                   &perf_script.tool);
        if (session == NULL)
                return -ENOMEM;
 
+       perf_script.session = session;
+
        if (cpu_list) {
                if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
                        return -1;
@@ -1384,7 +1407,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
                        return -1;
                }
 
-               err = scripting_ops->generate_script("perf-script");
+               err = scripting_ops->generate_script(session->pevent,
+                                                    "perf-script");
                goto out;
        }
 
index 07b5c7703dd10677e12a5b6e36c8603f18fd0f7e..861f0aec77aeacf099653d87ca9c6df9b6f2787c 100644 (file)
@@ -391,7 +391,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
 
        if (verbose) {
                fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
-                       event_name(counter), count[0], count[1], count[2]);
+                       perf_evsel__name(counter), count[0], count[1], count[2]);
        }
 
        /*
@@ -496,7 +496,7 @@ static int run_perf_stat(int argc __used, const char **argv)
                            errno == ENXIO) {
                                if (verbose)
                                        ui__warning("%s event is not supported by the kernel.\n",
-                                                   event_name(counter));
+                                                   perf_evsel__name(counter));
                                counter->supported = false;
                                continue;
                        }
@@ -594,7 +594,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
                        csv_output ? 0 : -4,
                        evsel_list->cpus->map[cpu], csv_sep);
 
-       fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel));
+       fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
 
        if (evsel->cgrp)
                fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -792,7 +792,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
        else
                cpu = 0;
 
-       fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel));
+       fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel));
 
        if (evsel->cgrp)
                fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
                        counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
                        csv_sep,
                        csv_output ? 0 : -24,
-                       event_name(counter));
+                       perf_evsel__name(counter));
 
                if (counter->cgrp)
                        fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
@@ -961,7 +961,7 @@ static void print_counter(struct perf_evsel *counter)
                                counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
                                csv_sep,
                                csv_output ? 0 : -24,
-                               event_name(counter));
+                               perf_evsel__name(counter));
 
                        if (counter->cgrp)
                                fprintf(output, "%s%s",
index 5a8727c0875772c9c37c3fc381b1812161c3b983..5ce30305462b1775fbfc80f9569e29328d25edd3 100644 (file)
@@ -583,7 +583,7 @@ static int test__basic_mmap(void)
                if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
                        pr_debug("expected %d %s events, got %d\n",
                                 expected_nr_events[evsel->idx],
-                                event_name(evsel), nr_events[evsel->idx]);
+                                perf_evsel__name(evsel), nr_events[evsel->idx]);
                        goto out_munmap;
                }
        }
index 6bb0277b7dfecdbf63e727592995480a409f16f5..e3cab5f088f8def4264a0ec65dba4f85b0b0f954 100644 (file)
@@ -245,7 +245,7 @@ static void perf_top__show_details(struct perf_top *top)
        if (notes->src == NULL)
                goto out_unlock;
 
-       printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name);
+       printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name);
        printf("  Events  Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
 
        more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
@@ -408,7 +408,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top)
        fprintf(stdout, "\t[e]     display entries (lines).           \t(%d)\n", top->print_entries);
 
        if (top->evlist->nr_entries > 1)
-               fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", event_name(top->sym_evsel));
+               fprintf(stdout, "\t[E]     active event counter.              \t(%s)\n", perf_evsel__name(top->sym_evsel));
 
        fprintf(stdout, "\t[f]     profile display filter (count).    \t(%d)\n", top->count_filter);
 
@@ -503,13 +503,13 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
                                fprintf(stderr, "\nAvailable events:");
 
                                list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
-                                       fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel));
+                                       fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel));
 
                                prompt_integer(&counter, "Enter details event counter");
 
                                if (counter >= top->evlist->nr_entries) {
                                        top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
-                                       fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel));
+                                       fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel));
                                        sleep(1);
                                        break;
                                }
@@ -774,7 +774,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
 
                if ((sort__has_parent || symbol_conf.use_callchain) &&
                    sample->callchain) {
-                       err = machine__resolve_callchain(machine, evsel, al.thread,
+                       err = machine__resolve_callchain(machine, al.thread,
                                                         sample->callchain, &parent);
                        if (err)
                                return;
@@ -960,7 +960,7 @@ try_again:
 
                        if (err == ENOENT) {
                                ui__error("The %s event is not supported.\n",
-                                           event_name(counter));
+                                         perf_evsel__name(counter));
                                goto out_err;
                        } else if (err == EMFILE) {
                                ui__error("Too many events are opened.\n"
index d9084e03ce56676628736c5814e27badbe2ef730..6c18785a6417986dabe47f775b0fd07067447012 100644 (file)
@@ -78,6 +78,19 @@ int main(int argc, char *argv[])
         return 0;
 }
 endef
+
+define SOURCE_GTK2_INFOBAR
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error \"-Wstrict-prototypes\"
+
+int main(void)
+{
+       gtk_info_bar_new();
+
+       return 0;
+}
+endef
 endif
 
 ifndef NO_LIBPERL
index 34b1c46eaf42c63d36ed5c36cbaceea38c2347a9..67a2703e666a360c1fd71a8af6ea150174ebeb70 100644 (file)
@@ -814,7 +814,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
 {
        struct disasm_line *pos, *n;
        struct annotation *notes;
-       const size_t size = symbol__size(sym);
+       size_t size;
        struct map_symbol ms = {
                .map = map,
                .sym = sym,
@@ -834,6 +834,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
        if (sym == NULL)
                return -1;
 
+       size = symbol__size(sym);
+
        if (map->dso->annotate_warned)
                return -1;
 
index 53f6697d014e788396b474c6be957893b8fd09ca..482f0517b61e20f61a18933133717ce53fc0e1c1 100644 (file)
@@ -23,6 +23,7 @@ struct hist_browser {
        struct hists        *hists;
        struct hist_entry   *he_selection;
        struct map_symbol   *selection;
+       int                  print_seq;
        bool                 has_symbols;
 };
 
@@ -800,6 +801,196 @@ do_offset:
        }
 }
 
+static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
+                                                       struct callchain_node *chain_node,
+                                                       u64 total, int level,
+                                                       FILE *fp)
+{
+       struct rb_node *node;
+       int offset = level * LEVEL_OFFSET_STEP;
+       u64 new_total, remaining;
+       int printed = 0;
+
+       if (callchain_param.mode == CHAIN_GRAPH_REL)
+               new_total = chain_node->children_hit;
+       else
+               new_total = total;
+
+       remaining = new_total;
+       node = rb_first(&chain_node->rb_root);
+       while (node) {
+               struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+               struct rb_node *next = rb_next(node);
+               u64 cumul = callchain_cumul_hits(child);
+               struct callchain_list *chain;
+               char folded_sign = ' ';
+               int first = true;
+               int extra_offset = 0;
+
+               remaining -= cumul;
+
+               list_for_each_entry(chain, &child->val, list) {
+                       char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+                       const char *str;
+                       bool was_first = first;
+
+                       if (first)
+                               first = false;
+                       else
+                               extra_offset = LEVEL_OFFSET_STEP;
+
+                       folded_sign = callchain_list__folded(chain);
+
+                       alloc_str = NULL;
+                       str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+                       if (was_first) {
+                               double percent = cumul * 100.0 / new_total;
+
+                               if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
+                                       str = "Not enough memory!";
+                               else
+                                       str = alloc_str;
+                       }
+
+                       printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
+                       free(alloc_str);
+                       if (folded_sign == '+')
+                               break;
+               }
+
+               if (folded_sign == '-') {
+                       const int new_level = level + (extra_offset ? 2 : 1);
+                       printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
+                                                                               new_level, fp);
+               }
+
+               node = next;
+       }
+
+       return printed;
+}
+
+static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
+                                               struct callchain_node *node,
+                                               int level, FILE *fp)
+{
+       struct callchain_list *chain;
+       int offset = level * LEVEL_OFFSET_STEP;
+       char folded_sign = ' ';
+       int printed = 0;
+
+       list_for_each_entry(chain, &node->val, list) {
+               char ipstr[BITS_PER_LONG / 4 + 1], *s;
+
+               folded_sign = callchain_list__folded(chain);
+               s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+               printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
+       }
+
+       if (folded_sign == '-')
+               printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
+                                                                       browser->hists->stats.total_period,
+                                                                       level + 1,  fp);
+       return printed;
+}
+
+static int hist_browser__fprintf_callchain(struct hist_browser *browser,
+                                          struct rb_root *chain, int level, FILE *fp)
+{
+       struct rb_node *nd;
+       int printed = 0;
+
+       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+
+               printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
+       }
+
+       return printed;
+}
+
+static int hist_browser__fprintf_entry(struct hist_browser *browser,
+                                      struct hist_entry *he, FILE *fp)
+{
+       char s[8192];
+       double percent;
+       int printed = 0;
+       char folded_sign = ' ';
+
+       if (symbol_conf.use_callchain)
+               folded_sign = hist_entry__folded(he);
+
+       hist_entry__snprintf(he, s, sizeof(s), browser->hists);
+       percent = (he->period * 100.0) / browser->hists->stats.total_period;
+
+       if (symbol_conf.use_callchain)
+               printed += fprintf(fp, "%c ", folded_sign);
+
+       printed += fprintf(fp, " %5.2f%%", percent);
+
+       if (symbol_conf.show_nr_samples)
+               printed += fprintf(fp, " %11u", he->nr_events);
+
+       if (symbol_conf.show_total_period)
+               printed += fprintf(fp, " %12" PRIu64, he->period);
+
+       printed += fprintf(fp, "%s\n", rtrim(s));
+
+       if (folded_sign == '-')
+               printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);
+
+       return printed;
+}
+
+static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
+{
+       struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
+       int printed = 0;
+
+       while (nd) {
+               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+               printed += hist_browser__fprintf_entry(browser, h, fp);
+               nd = hists__filter_entries(rb_next(nd));
+       }
+
+       return printed;
+}
+
+static int hist_browser__dump(struct hist_browser *browser)
+{
+       char filename[64];
+       FILE *fp;
+
+       while (1) {
+               scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
+               if (access(filename, F_OK))
+                       break;
+               /*
+                * XXX: Just an arbitrary lazy upper limit
+                */
+               if (++browser->print_seq == 8192) {
+                       ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
+                       return -1;
+               }
+       }
+
+       fp = fopen(filename, "w");
+       if (fp == NULL) {
+               char bf[64];
+               strerror_r(errno, bf, sizeof(bf));
+               ui_helpline__fpush("Couldn't write to %s: %s", filename, bf);
+               return -1;
+       }
+
+       ++browser->print_seq;
+       hist_browser__fprintf(browser, fp);
+       fclose(fp);
+       ui_helpline__fpush("%s written!", filename);
+
+       return 0;
+}
+
 static struct hist_browser *hist_browser__new(struct hists *hists)
 {
        struct hist_browser *browser = zalloc(sizeof(*browser));
@@ -937,6 +1128,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                            browser->selection->map->dso->annotate_warned)
                                continue;
                        goto do_annotate;
+               case 'P':
+                       hist_browser__dump(browser);
+                       continue;
                case 'd':
                        goto zoom_dso;
                case 't':
@@ -969,6 +1163,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                                        "E             Expand all callchains\n"
                                        "d             Zoom into current DSO\n"
                                        "t             Zoom into current Thread\n"
+                                       "P             Print histograms to perf.hist.N\n"
                                        "/             Filter symbol by name");
                        continue;
                case K_ENTER:
@@ -1172,7 +1367,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
        struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
        bool current_entry = ui_browser__is_current_entry(browser, row);
        unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
-       const char *ev_name = event_name(evsel);
+       const char *ev_name = perf_evsel__name(evsel);
        char bf[256], unit;
        const char *warn = " ";
        size_t printed;
@@ -1240,7 +1435,7 @@ browse_hists:
                         */
                        if (timer)
                                timer(arg);
-                       ev_name = event_name(pos);
+                       ev_name = perf_evsel__name(pos);
                        key = perf_evsel__hists_browse(pos, nr_events, help,
                                                       ev_name, true, timer,
                                                       arg, delay_secs);
@@ -1309,17 +1504,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
        ui_helpline__push("Press ESC to exit");
 
        list_for_each_entry(pos, &evlist->entries, node) {
-               const char *ev_name = event_name(pos);
+               const char *ev_name = perf_evsel__name(pos);
                size_t line_len = strlen(ev_name) + 7;
 
                if (menu.b.width < line_len)
                        menu.b.width = line_len;
-               /*
-                * Cache the evsel name, tracepoints have a _high_ cost per
-                * event_name() call.
-                */
-               if (pos->name == NULL)
-                       pos->name = strdup(ev_name);
        }
 
        return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
@@ -1330,11 +1519,10 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
                                  void(*timer)(void *arg), void *arg,
                                  int delay_secs)
 {
-
        if (evlist->nr_entries == 1) {
                struct perf_evsel *first = list_entry(evlist->entries.next,
                                                      struct perf_evsel, node);
-               const char *ev_name = event_name(first);
+               const char *ev_name = perf_evsel__name(first);
                return perf_evsel__hists_browse(first, evlist->nr_entries, help,
                                                ev_name, false, timer, arg,
                                                delay_secs);
index 0656c381a89cae7dcfd92302ea2c021ca75b517c..ec12e0b4ded6567d1c673049cf39cea0f93891f0 100644 (file)
@@ -11,8 +11,8 @@
 
 static void perf_gtk__signal(int sig)
 {
+       perf_gtk__exit(false);
        psignal(sig, "perf");
-       gtk_main_quit();
 }
 
 static void perf_gtk__resize_window(GtkWidget *window)
@@ -122,13 +122,59 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
        gtk_container_add(GTK_CONTAINER(window), view);
 }
 
+#ifdef HAVE_GTK_INFO_BAR
+static GtkWidget *perf_gtk__setup_info_bar(void)
+{
+       GtkWidget *info_bar;
+       GtkWidget *label;
+       GtkWidget *content_area;
+
+       info_bar = gtk_info_bar_new();
+       gtk_widget_set_no_show_all(info_bar, TRUE);
+
+       label = gtk_label_new("");
+       gtk_widget_show(label);
+
+       content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar));
+       gtk_container_add(GTK_CONTAINER(content_area), label);
+
+       gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK,
+                               GTK_RESPONSE_OK);
+       g_signal_connect(info_bar, "response",
+                        G_CALLBACK(gtk_widget_hide), NULL);
+
+       pgctx->info_bar = info_bar;
+       pgctx->message_label = label;
+
+       return info_bar;
+}
+#endif
+
+static GtkWidget *perf_gtk__setup_statusbar(void)
+{
+       GtkWidget *stbar;
+       unsigned ctxid;
+
+       stbar = gtk_statusbar_new();
+
+       ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar),
+                                            "perf report");
+       pgctx->statbar = stbar;
+       pgctx->statbar_ctx_id = ctxid;
+
+       return stbar;
+}
+
 int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
                                  const char *help __used,
                                  void (*timer) (void *arg)__used,
                                  void *arg __used, int delay_secs __used)
 {
        struct perf_evsel *pos;
+       GtkWidget *vbox;
        GtkWidget *notebook;
+       GtkWidget *info_bar;
+       GtkWidget *statbar;
        GtkWidget *window;
 
        signal(SIGSEGV, perf_gtk__signal);
@@ -143,11 +189,17 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 
        g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
 
+       pgctx = perf_gtk__activate_context(window);
+       if (!pgctx)
+               return -1;
+
+       vbox = gtk_vbox_new(FALSE, 0);
+
        notebook = gtk_notebook_new();
 
        list_for_each_entry(pos, &evlist->entries, node) {
                struct hists *hists = &pos->hists;
-               const char *evname = event_name(pos);
+               const char *evname = perf_evsel__name(pos);
                GtkWidget *scrolled_window;
                GtkWidget *tab_label;
 
@@ -164,7 +216,16 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
                gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
        }
 
-       gtk_container_add(GTK_CONTAINER(window), notebook);
+       gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+       info_bar = perf_gtk__setup_info_bar();
+       if (info_bar)
+               gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
+
+       statbar = perf_gtk__setup_statusbar();
+       gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+       gtk_container_add(GTK_CONTAINER(window), vbox);
 
        gtk_widget_show_all(window);
 
@@ -174,5 +235,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
 
        gtk_main();
 
+       perf_gtk__deactivate_context(&pgctx);
+
        return 0;
 }
index 75177ee04032d06a3862acf4befd82b0b67516d3..a4d0f2b4a2dcf4c4b6bfb9b21a52aabc4b9376ca 100644 (file)
@@ -1,8 +1,39 @@
 #ifndef _PERF_GTK_H_
 #define _PERF_GTK_H_ 1
 
+#include <stdbool.h>
+
 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
 #include <gtk/gtk.h>
 #pragma GCC diagnostic error "-Wstrict-prototypes"
 
+
+struct perf_gtk_context {
+       GtkWidget *main_window;
+
+#ifdef HAVE_GTK_INFO_BAR
+       GtkWidget *info_bar;
+       GtkWidget *message_label;
+#endif
+       GtkWidget *statbar;
+       guint statbar_ctx_id;
+};
+
+extern struct perf_gtk_context *pgctx;
+
+static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx)
+{
+       return ctx && ctx->main_window;
+}
+
+struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
+int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
+
+#ifndef HAVE_GTK_INFO_BAR
+static inline GtkWidget *perf_gtk__setup_info_bar(void)
+{
+       return NULL;
+}
+#endif
+
 #endif /* _PERF_GTK_H_ */
index 8295299577660b24b99405a22965316f04f96e98..92879ce61e2fc0059f6827c38b9ff8eaf114adba 100644 (file)
@@ -1,12 +1,17 @@
 #include "gtk.h"
 #include "../../util/cache.h"
+#include "../../util/debug.h"
+
+extern struct perf_error_ops perf_gtk_eops;
 
 int perf_gtk__init(void)
 {
+       perf_error__register(&perf_gtk_eops);
        return gtk_init_check(NULL, NULL) ? 0 : -1;
 }
 
 void perf_gtk__exit(bool wait_for_ok __used)
 {
+       perf_error__unregister(&perf_gtk_eops);
        gtk_main_quit();
 }
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
new file mode 100644 (file)
index 0000000..0ead373
--- /dev/null
@@ -0,0 +1,129 @@
+#include "../util.h"
+#include "../../util/debug.h"
+#include "gtk.h"
+
+#include <string.h>
+
+
+struct perf_gtk_context *pgctx;
+
+struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window)
+{
+       struct perf_gtk_context *ctx;
+
+       ctx = malloc(sizeof(*pgctx));
+       if (ctx)
+               ctx->main_window = window;
+
+       return ctx;
+}
+
+int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
+{
+       if (!perf_gtk__is_active_context(*ctx))
+               return -1;
+
+       free(*ctx);
+       *ctx = NULL;
+       return 0;
+}
+
+static int perf_gtk__error(const char *format, va_list args)
+{
+       char *msg;
+       GtkWidget *dialog;
+
+       if (!perf_gtk__is_active_context(pgctx) ||
+           vasprintf(&msg, format, args) < 0) {
+               fprintf(stderr, "Error:\n");
+               vfprintf(stderr, format, args);
+               fprintf(stderr, "\n");
+               return -1;
+       }
+
+       dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_window),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_ERROR,
+                                       GTK_BUTTONS_CLOSE,
+                                       "<b>Error</b>\n\n%s", msg);
+       gtk_dialog_run(GTK_DIALOG(dialog));
+
+       gtk_widget_destroy(dialog);
+       free(msg);
+       return 0;
+}
+
+#ifdef HAVE_GTK_INFO_BAR
+static int perf_gtk__warning_info_bar(const char *format, va_list args)
+{
+       char *msg;
+
+       if (!perf_gtk__is_active_context(pgctx) ||
+           vasprintf(&msg, format, args) < 0) {
+               fprintf(stderr, "Warning:\n");
+               vfprintf(stderr, format, args);
+               fprintf(stderr, "\n");
+               return -1;
+       }
+
+       gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg);
+       gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar),
+                                     GTK_MESSAGE_WARNING);
+       gtk_widget_show(pgctx->info_bar);
+
+       free(msg);
+       return 0;
+}
+#else
+static int perf_gtk__warning_statusbar(const char *format, va_list args)
+{
+       char *msg, *p;
+
+       if (!perf_gtk__is_active_context(pgctx) ||
+           vasprintf(&msg, format, args) < 0) {
+               fprintf(stderr, "Warning:\n");
+               vfprintf(stderr, format, args);
+               fprintf(stderr, "\n");
+               return -1;
+       }
+
+       gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar),
+                         pgctx->statbar_ctx_id);
+
+       /* Only first line can be displayed */
+       p = strchr(msg, '\n');
+       if (p)
+               *p = '\0';
+
+       gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar),
+                          pgctx->statbar_ctx_id, msg);
+
+       free(msg);
+       return 0;
+}
+#endif
+
+struct perf_error_ops perf_gtk_eops = {
+       .error          = perf_gtk__error,
+#ifdef HAVE_GTK_INFO_BAR
+       .warning        = perf_gtk__warning_info_bar,
+#else
+       .warning        = perf_gtk__warning_statusbar,
+#endif
+};
+
+/*
+ * FIXME: Functions below should be implemented properly.
+ *        For now, just add stubs for NO_NEWT=1 build.
+ */
+#ifdef NO_NEWT_SUPPORT
+int ui_helpline__show_help(const char *format __used, va_list ap __used)
+{
+       return 0;
+}
+
+void ui_progress__update(u64 curr __used, u64 total __used,
+                        const char *title __used)
+{
+}
+#endif
index d33e943ac434608067fe54fb734cda5a02d1d991..e813c1d173463564a496bdd3917f3079089a3101 100644 (file)
@@ -15,6 +15,8 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
 
 static volatile int ui__need_resize;
 
+extern struct perf_error_ops perf_tui_eops;
+
 void ui__refresh_dimensions(bool force)
 {
        if (force || ui__need_resize) {
@@ -122,6 +124,8 @@ int ui__init(void)
        signal(SIGINT, ui__signal);
        signal(SIGQUIT, ui__signal);
        signal(SIGTERM, ui__signal);
+
+       perf_error__register(&perf_tui_eops);
 out:
        return err;
 }
@@ -137,4 +141,6 @@ void ui__exit(bool wait_for_ok)
        SLsmg_refresh();
        SLsmg_reset_smg();
        SLang_reset_tty();
+
+       perf_error__unregister(&perf_tui_eops);
 }
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
new file mode 100644 (file)
index 0000000..092902e
--- /dev/null
@@ -0,0 +1,243 @@
+#include "../../util/util.h"
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/ttydefaults.h>
+
+#include "../../util/cache.h"
+#include "../../util/debug.h"
+#include "../browser.h"
+#include "../keysyms.h"
+#include "../helpline.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../libslang.h"
+
+static void ui_browser__argv_write(struct ui_browser *browser,
+                                  void *entry, int row)
+{
+       char **arg = entry;
+       bool current_entry = ui_browser__is_current_entry(browser, row);
+
+       ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
+                                                      HE_COLORSET_NORMAL);
+       slsmg_write_nstring(*arg, browser->width);
+}
+
+static int popup_menu__run(struct ui_browser *menu)
+{
+       int key;
+
+       if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
+               return -1;
+
+       while (1) {
+               key = ui_browser__run(menu, 0);
+
+               switch (key) {
+               case K_RIGHT:
+               case K_ENTER:
+                       key = menu->index;
+                       break;
+               case K_LEFT:
+               case K_ESC:
+               case 'q':
+               case CTRL('c'):
+                       key = -1;
+                       break;
+               default:
+                       continue;
+               }
+
+               break;
+       }
+
+       ui_browser__hide(menu);
+       return key;
+}
+
+int ui__popup_menu(int argc, char * const argv[])
+{
+       struct ui_browser menu = {
+               .entries    = (void *)argv,
+               .refresh    = ui_browser__argv_refresh,
+               .seek       = ui_browser__argv_seek,
+               .write      = ui_browser__argv_write,
+               .nr_entries = argc,
+       };
+
+       return popup_menu__run(&menu);
+}
+
+int ui_browser__input_window(const char *title, const char *text, char *input,
+                            const char *exit_msg, int delay_secs)
+{
+       int x, y, len, key;
+       int max_len = 60, nr_lines = 0;
+       static char buf[50];
+       const char *t;
+
+       t = text;
+       while (1) {
+               const char *sep = strchr(t, '\n');
+
+               if (sep == NULL)
+                       sep = strchr(t, '\0');
+               len = sep - t;
+               if (max_len < len)
+                       max_len = len;
+               ++nr_lines;
+               if (*sep == '\0')
+                       break;
+               t = sep + 1;
+       }
+
+       max_len += 2;
+       nr_lines += 8;
+       y = SLtt_Screen_Rows / 2 - nr_lines / 2;
+       x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+       SLsmg_set_color(0);
+       SLsmg_draw_box(y, x++, nr_lines, max_len);
+       if (title) {
+               SLsmg_gotorc(y, x + 1);
+               SLsmg_write_string((char *)title);
+       }
+       SLsmg_gotorc(++y, x);
+       nr_lines -= 7;
+       max_len -= 2;
+       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+                                  nr_lines, max_len, 1);
+       y += nr_lines;
+       len = 5;
+       while (len--) {
+               SLsmg_gotorc(y + len - 1, x);
+               SLsmg_write_nstring((char *)" ", max_len);
+       }
+       SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
+
+       SLsmg_gotorc(y + 3, x);
+       SLsmg_write_nstring((char *)exit_msg, max_len);
+       SLsmg_refresh();
+
+       x += 2;
+       len = 0;
+       key = ui__getch(delay_secs);
+       while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
+               if (key == K_BKSPC) {
+                       if (len == 0)
+                               goto next_key;
+                       SLsmg_gotorc(y, x + --len);
+                       SLsmg_write_char(' ');
+               } else {
+                       buf[len] = key;
+                       SLsmg_gotorc(y, x + len++);
+                       SLsmg_write_char(key);
+               }
+               SLsmg_refresh();
+
+               /* XXX more graceful overflow handling needed */
+               if (len == sizeof(buf) - 1) {
+                       ui_helpline__push("maximum size of symbol name reached!");
+                       key = K_ENTER;
+                       break;
+               }
+next_key:
+               key = ui__getch(delay_secs);
+       }
+
+       buf[len] = '\0';
+       strncpy(input, buf, len+1);
+       return key;
+}
+
+int ui__question_window(const char *title, const char *text,
+                       const char *exit_msg, int delay_secs)
+{
+       int x, y;
+       int max_len = 0, nr_lines = 0;
+       const char *t;
+
+       t = text;
+       while (1) {
+               const char *sep = strchr(t, '\n');
+               int len;
+
+               if (sep == NULL)
+                       sep = strchr(t, '\0');
+               len = sep - t;
+               if (max_len < len)
+                       max_len = len;
+               ++nr_lines;
+               if (*sep == '\0')
+                       break;
+               t = sep + 1;
+       }
+
+       max_len += 2;
+       nr_lines += 4;
+       y = SLtt_Screen_Rows / 2 - nr_lines / 2,
+       x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+       SLsmg_set_color(0);
+       SLsmg_draw_box(y, x++, nr_lines, max_len);
+       if (title) {
+               SLsmg_gotorc(y, x + 1);
+               SLsmg_write_string((char *)title);
+       }
+       SLsmg_gotorc(++y, x);
+       nr_lines -= 2;
+       max_len -= 2;
+       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+                                  nr_lines, max_len, 1);
+       SLsmg_gotorc(y + nr_lines - 2, x);
+       SLsmg_write_nstring((char *)" ", max_len);
+       SLsmg_gotorc(y + nr_lines - 1, x);
+       SLsmg_write_nstring((char *)exit_msg, max_len);
+       SLsmg_refresh();
+       return ui__getch(delay_secs);
+}
+
+int ui__help_window(const char *text)
+{
+       return ui__question_window("Help", text, "Press any key...", 0);
+}
+
+int ui__dialog_yesno(const char *msg)
+{
+       return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
+}
+
+static int __ui__warning(const char *title, const char *format, va_list args)
+{
+       char *s;
+
+       if (vasprintf(&s, format, args) > 0) {
+               int key;
+
+               pthread_mutex_lock(&ui__lock);
+               key = ui__question_window(title, s, "Press any key...", 0);
+               pthread_mutex_unlock(&ui__lock);
+               free(s);
+               return key;
+       }
+
+       fprintf(stderr, "%s\n", title);
+       vfprintf(stderr, format, args);
+       return K_ESC;
+}
+
+static int perf_tui__error(const char *format, va_list args)
+{
+       return __ui__warning("Error:", format, args);
+}
+
+static int perf_tui__warning(const char *format, va_list args)
+{
+       return __ui__warning("Warning:", format, args);
+}
+
+struct perf_error_ops perf_tui_eops = {
+       .error          = perf_tui__error,
+       .warning        = perf_tui__warning,
+};
index ad4374a16bb08b88c008ca6e79fcf4a5b15903b5..4f989774c8c674c535990dcf82ae2ba47d5971e3 100644 (file)
-#include "../util.h"
-#include <signal.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/ttydefaults.h>
-
-#include "../cache.h"
-#include "../debug.h"
-#include "browser.h"
-#include "keysyms.h"
-#include "helpline.h"
-#include "ui.h"
 #include "util.h"
-#include "libslang.h"
-
-static void ui_browser__argv_write(struct ui_browser *browser,
-                                  void *entry, int row)
-{
-       char **arg = entry;
-       bool current_entry = ui_browser__is_current_entry(browser, row);
-
-       ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
-                                                      HE_COLORSET_NORMAL);
-       slsmg_write_nstring(*arg, browser->width);
-}
-
-static int popup_menu__run(struct ui_browser *menu)
-{
-       int key;
-
-       if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
-               return -1;
+#include "../debug.h"
 
-       while (1) {
-               key = ui_browser__run(menu, 0);
-
-               switch (key) {
-               case K_RIGHT:
-               case K_ENTER:
-                       key = menu->index;
-                       break;
-               case K_LEFT:
-               case K_ESC:
-               case 'q':
-               case CTRL('c'):
-                       key = -1;
-                       break;
-               default:
-                       continue;
-               }
-
-               break;
-       }
-
-       ui_browser__hide(menu);
-       return key;
-}
 
-int ui__popup_menu(int argc, char * const argv[])
+/*
+ * Default error logging functions
+ */
+static int perf_stdio__error(const char *format, va_list args)
 {
-       struct ui_browser menu = {
-               .entries    = (void *)argv,
-               .refresh    = ui_browser__argv_refresh,
-               .seek       = ui_browser__argv_seek,
-               .write      = ui_browser__argv_write,
-               .nr_entries = argc,
-       };
-
-       return popup_menu__run(&menu);
+       fprintf(stderr, "Error:\n");
+       vfprintf(stderr, format, args);
+       return 0;
 }
 
-int ui_browser__input_window(const char *title, const char *text, char *input,
-                            const char *exit_msg, int delay_secs)
+static int perf_stdio__warning(const char *format, va_list args)
 {
-       int x, y, len, key;
-       int max_len = 60, nr_lines = 0;
-       static char buf[50];
-       const char *t;
-
-       t = text;
-       while (1) {
-               const char *sep = strchr(t, '\n');
-
-               if (sep == NULL)
-                       sep = strchr(t, '\0');
-               len = sep - t;
-               if (max_len < len)
-                       max_len = len;
-               ++nr_lines;
-               if (*sep == '\0')
-                       break;
-               t = sep + 1;
-       }
-
-       max_len += 2;
-       nr_lines += 8;
-       y = SLtt_Screen_Rows / 2 - nr_lines / 2;
-       x = SLtt_Screen_Cols / 2 - max_len / 2;
-
-       SLsmg_set_color(0);
-       SLsmg_draw_box(y, x++, nr_lines, max_len);
-       if (title) {
-               SLsmg_gotorc(y, x + 1);
-               SLsmg_write_string((char *)title);
-       }
-       SLsmg_gotorc(++y, x);
-       nr_lines -= 7;
-       max_len -= 2;
-       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
-                                  nr_lines, max_len, 1);
-       y += nr_lines;
-       len = 5;
-       while (len--) {
-               SLsmg_gotorc(y + len - 1, x);
-               SLsmg_write_nstring((char *)" ", max_len);
-       }
-       SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
-
-       SLsmg_gotorc(y + 3, x);
-       SLsmg_write_nstring((char *)exit_msg, max_len);
-       SLsmg_refresh();
-
-       x += 2;
-       len = 0;
-       key = ui__getch(delay_secs);
-       while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
-               if (key == K_BKSPC) {
-                       if (len == 0)
-                               goto next_key;
-                       SLsmg_gotorc(y, x + --len);
-                       SLsmg_write_char(' ');
-               } else {
-                       buf[len] = key;
-                       SLsmg_gotorc(y, x + len++);
-                       SLsmg_write_char(key);
-               }
-               SLsmg_refresh();
-
-               /* XXX more graceful overflow handling needed */
-               if (len == sizeof(buf) - 1) {
-                       ui_helpline__push("maximum size of symbol name reached!");
-                       key = K_ENTER;
-                       break;
-               }
-next_key:
-               key = ui__getch(delay_secs);
-       }
-
-       buf[len] = '\0';
-       strncpy(input, buf, len+1);
-       return key;
+       fprintf(stderr, "Warning:\n");
+       vfprintf(stderr, format, args);
+       return 0;
 }
 
-int ui__question_window(const char *title, const char *text,
-                       const char *exit_msg, int delay_secs)
+static struct perf_error_ops default_eops =
 {
-       int x, y;
-       int max_len = 0, nr_lines = 0;
-       const char *t;
-
-       t = text;
-       while (1) {
-               const char *sep = strchr(t, '\n');
-               int len;
-
-               if (sep == NULL)
-                       sep = strchr(t, '\0');
-               len = sep - t;
-               if (max_len < len)
-                       max_len = len;
-               ++nr_lines;
-               if (*sep == '\0')
-                       break;
-               t = sep + 1;
-       }
-
-       max_len += 2;
-       nr_lines += 4;
-       y = SLtt_Screen_Rows / 2 - nr_lines / 2,
-       x = SLtt_Screen_Cols / 2 - max_len / 2;
-
-       SLsmg_set_color(0);
-       SLsmg_draw_box(y, x++, nr_lines, max_len);
-       if (title) {
-               SLsmg_gotorc(y, x + 1);
-               SLsmg_write_string((char *)title);
-       }
-       SLsmg_gotorc(++y, x);
-       nr_lines -= 2;
-       max_len -= 2;
-       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
-                                  nr_lines, max_len, 1);
-       SLsmg_gotorc(y + nr_lines - 2, x);
-       SLsmg_write_nstring((char *)" ", max_len);
-       SLsmg_gotorc(y + nr_lines - 1, x);
-       SLsmg_write_nstring((char *)exit_msg, max_len);
-       SLsmg_refresh();
-       return ui__getch(delay_secs);
-}
+       .error          = perf_stdio__error,
+       .warning        = perf_stdio__warning,
+};
 
-int ui__help_window(const char *text)
-{
-       return ui__question_window("Help", text, "Press any key...", 0);
-}
+static struct perf_error_ops *perf_eops = &default_eops;
 
-int ui__dialog_yesno(const char *msg)
-{
-       return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
-}
 
-int __ui__warning(const char *title, const char *format, va_list args)
+int ui__error(const char *format, ...)
 {
-       char *s;
-
-       if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
-               int key;
+       int ret;
+       va_list args;
 
-               pthread_mutex_lock(&ui__lock);
-               key = ui__question_window(title, s, "Press any key...", 0);
-               pthread_mutex_unlock(&ui__lock);
-               free(s);
-               return key;
-       }
+       va_start(args, format);
+       ret = perf_eops->error(format, args);
+       va_end(args);
 
-       fprintf(stderr, "%s:\n", title);
-       vfprintf(stderr, format, args);
-       return K_ESC;
+       return ret;
 }
 
 int ui__warning(const char *format, ...)
 {
-       int key;
+       int ret;
        va_list args;
 
        va_start(args, format);
-       key = __ui__warning("Warning", format, args);
+       ret = perf_eops->warning(format, args);
        va_end(args);
-       return key;
+
+       return ret;
 }
 
-int ui__error(const char *format, ...)
+
+/**
+ * perf_error__register - Register error logging functions
+ * @eops: The pointer to error logging function struct
+ *
+ * Register UI-specific error logging functions. Before calling this,
+ * other logging functions should be unregistered, if any.
+ */
+int perf_error__register(struct perf_error_ops *eops)
 {
-       int key;
-       va_list args;
+       if (perf_eops != &default_eops)
+               return -1;
 
-       va_start(args, format);
-       key = __ui__warning("Error", format, args);
-       va_end(args);
-       return key;
+       perf_eops = eops;
+       return 0;
+}
+
+/**
+ * perf_error__unregister - Unregister error logging functions
+ * @eops: The pointer to error logging function struct
+ *
+ * Unregister already registered error logging functions.
+ */
+int perf_error__unregister(struct perf_error_ops *eops)
+{
+       if (perf_eops != eops)
+               return -1;
+
+       perf_eops = &default_eops;
+       return 0;
 }
index 2d1738bd71c8adc639e7e53919f2cf988ea07ec3..361f08c52d37cba6acf8056cba96f297ceb25515 100644 (file)
@@ -9,6 +9,13 @@ int ui__help_window(const char *text);
 int ui__dialog_yesno(const char *msg);
 int ui__question_window(const char *title, const char *text,
                        const char *exit_msg, int delay_secs);
-int __ui__warning(const char *title, const char *format, va_list args);
+
+struct perf_error_ops {
+       int (*error)(const char *format, va_list args);
+       int (*warning)(const char *format, va_list args);
+};
+
+int perf_error__register(struct perf_error_ops *eops);
+int perf_error__unregister(struct perf_error_ops *eops);
 
 #endif /* _PERF_UI_UTIL_H_ */
index efb1fce259a4f2ea9ae202a9111976daf497bb53..4dfe0bb3c3225455e4f0ff3b1cb74a386352db3c 100644 (file)
@@ -47,7 +47,7 @@ int dump_printf(const char *fmt, ...)
        return ret;
 }
 
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
 int ui__warning(const char *format, ...)
 {
        va_list args;
index 6bebe7f0a20c6cb6b12cac9d041203d3221f2b1a..015c91dbc096310554ba6f7bcec51c16d7cabfac 100644 (file)
@@ -12,8 +12,9 @@ int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(union perf_event *event);
 
 struct ui_progress;
+struct perf_error_ops;
 
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
 static inline int ui_helpline__show_help(const char *format __used, va_list ap __used)
 {
        return 0;
@@ -23,12 +24,28 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
                                       const char *title __used) {}
 
 #define ui__error(format, arg...) ui__warning(format, ##arg)
-#else
+
+static inline int
+perf_error__register(struct perf_error_ops *eops __used)
+{
+       return 0;
+}
+
+static inline int
+perf_error__unregister(struct perf_error_ops *eops __used)
+{
+       return 0;
+}
+
+#else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
+
 extern char ui_helpline__last_msg[];
 int ui_helpline__show_help(const char *format, va_list ap);
 #include "../ui/progress.h"
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-#endif
+#include "../ui/util.h"
+
+#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
 
 int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
 int ui__error_paranoid(void);
index 7400fb3fc50c91910a51eb3dc6a679ca6e4a05de..f74e9560350eb3dccfe7cc47c6a13e6256f91bb4 100644 (file)
@@ -224,8 +224,8 @@ out_free_attrs:
        return err;
 }
 
-static struct perf_evsel *
-       perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
+struct perf_evsel *
+perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
 {
        struct perf_evsel *evsel;
 
index 989bee9624c23c66e002b7a245c89c7114f3b219..40d4d3cdced0e081ec41863abe6ab46c562a3e3a 100644 (file)
@@ -73,6 +73,9 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
 #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
        perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
 
+struct perf_evsel *
+perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
+
 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
                         int cpu, int thread, u64 id);
 
index 9f6cebd798eed5ee44ea4510305b93b4f2e3fd6b..e81771364867bd2b5d7bf52e38e9ae0984316a0a 100644 (file)
@@ -15,7 +15,7 @@
 #include "cpumap.h"
 #include "thread_map.h"
 #include "target.h"
-#include "../../include/linux/perf_event.h"
+#include "../../../include/linux/hw_breakpoint.h"
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@@ -78,7 +78,7 @@ static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
        "ref-cycles",
 };
 
-const char *__perf_evsel__hw_name(u64 config)
+static const char *__perf_evsel__hw_name(u64 config)
 {
        if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
                return perf_evsel__hw_names[config];
@@ -86,16 +86,15 @@ const char *__perf_evsel__hw_name(u64 config)
        return "unknown-hardware";
 }
 
-static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
+static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size)
 {
-       int colon = 0;
+       int colon = 0, r = 0;
        struct perf_event_attr *attr = &evsel->attr;
-       int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config));
        bool exclude_guest_default = false;
 
 #define MOD_PRINT(context, mod)        do {                                    \
                if (!attr->exclude_##context) {                         \
-                       if (!colon) colon = r++;                        \
+                       if (!colon) colon = ++r;                        \
                        r += scnprintf(bf + r, size - r, "%c", mod);    \
                } } while(0)
 
@@ -108,7 +107,7 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
 
        if (attr->precise_ip) {
                if (!colon)
-                       colon = r++;
+                       colon = ++r;
                r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
                exclude_guest_default = true;
        }
@@ -119,39 +118,211 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
        }
 #undef MOD_PRINT
        if (colon)
-               bf[colon] = ':';
+               bf[colon - 1] = ':';
        return r;
 }
 
-int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
+static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+       int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config));
+       return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+}
+
+static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
+       "cpu-clock",
+       "task-clock",
+       "page-faults",
+       "context-switches",
+       "CPU-migrations",
+       "minor-faults",
+       "major-faults",
+       "alignment-faults",
+       "emulation-faults",
+};
+
+static const char *__perf_evsel__sw_name(u64 config)
 {
-       int ret;
+       if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
+               return perf_evsel__sw_names[config];
+       return "unknown-software";
+}
+
+static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+       int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config));
+       return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+}
+
+static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)
+{
+       int r;
+
+       r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr);
+
+       if (type & HW_BREAKPOINT_R)
+               r += scnprintf(bf + r, size - r, "r");
+
+       if (type & HW_BREAKPOINT_W)
+               r += scnprintf(bf + r, size - r, "w");
+
+       if (type & HW_BREAKPOINT_X)
+               r += scnprintf(bf + r, size - r, "x");
+
+       return r;
+}
+
+static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+       struct perf_event_attr *attr = &evsel->attr;
+       int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type);
+       return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
+}
+
+const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_EVSEL__MAX_ALIASES] = {
+ { "L1-dcache",        "l1-d",         "l1d",          "L1-data",              },
+ { "L1-icache",        "l1-i",         "l1i",          "L1-instruction",       },
+ { "LLC",      "L2",                                                   },
+ { "dTLB",     "d-tlb",        "Data-TLB",                             },
+ { "iTLB",     "i-tlb",        "Instruction-TLB",                      },
+ { "branch",   "branches",     "bpu",          "btb",          "bpc",  },
+ { "node",                                                             },
+};
+
+const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+                                  [PERF_EVSEL__MAX_ALIASES] = {
+ { "load",     "loads",        "read",                                 },
+ { "store",    "stores",       "write",                                },
+ { "prefetch", "prefetches",   "speculative-read", "speculative-load", },
+};
+
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+                                      [PERF_EVSEL__MAX_ALIASES] = {
+ { "refs",     "Reference",    "ops",          "access",               },
+ { "misses",   "miss",                                                 },
+};
+
+#define C(x)           PERF_COUNT_HW_CACHE_##x
+#define CACHE_READ     (1 << C(OP_READ))
+#define CACHE_WRITE    (1 << C(OP_WRITE))
+#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
+#define COP(x)         (1 << x)
+
+/*
+ * cache operartion stat
+ * L1I : Read and prefetch only
+ * ITLB and BPU : Read-only
+ */
+static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
+ [C(L1D)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(L1I)]      = (CACHE_READ | CACHE_PREFETCH),
+ [C(LL)]       = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(DTLB)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+ [C(ITLB)]     = (CACHE_READ),
+ [C(BPU)]      = (CACHE_READ),
+ [C(NODE)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
+};
+
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op)
+{
+       if (perf_evsel__hw_cache_stat[type] & COP(op))
+               return true;    /* valid */
+       else
+               return false;   /* invalid */
+}
+
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+                                           char *bf, size_t size)
+{
+       if (result) {
+               return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
+                                perf_evsel__hw_cache_op[op][0],
+                                perf_evsel__hw_cache_result[result][0]);
+       }
+
+       return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
+                        perf_evsel__hw_cache_op[op][1]);
+}
+
+static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size)
+{
+       u8 op, result, type = (config >>  0) & 0xff;
+       const char *err = "unknown-ext-hardware-cache-type";
+
+       if (type > PERF_COUNT_HW_CACHE_MAX)
+               goto out_err;
+
+       op = (config >>  8) & 0xff;
+       err = "unknown-ext-hardware-cache-op";
+       if (op > PERF_COUNT_HW_CACHE_OP_MAX)
+               goto out_err;
+
+       result = (config >> 16) & 0xff;
+       err = "unknown-ext-hardware-cache-result";
+       if (result > PERF_COUNT_HW_CACHE_RESULT_MAX)
+               goto out_err;
+
+       err = "invalid-cache";
+       if (!perf_evsel__is_cache_op_valid(type, op))
+               goto out_err;
+
+       return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size);
+out_err:
+       return scnprintf(bf, size, "%s", err);
+}
+
+static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+       int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size);
+       return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+}
+
+static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size)
+{
+       int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
+       return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret);
+}
+
+const char *perf_evsel__name(struct perf_evsel *evsel)
+{
+       char bf[128];
+
+       if (evsel->name)
+               return evsel->name;
 
        switch (evsel->attr.type) {
        case PERF_TYPE_RAW:
-               ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
+               perf_evsel__raw_name(evsel, bf, sizeof(bf));
                break;
 
        case PERF_TYPE_HARDWARE:
-               ret = perf_evsel__hw_name(evsel, bf, size);
+               perf_evsel__hw_name(evsel, bf, sizeof(bf));
+               break;
+
+       case PERF_TYPE_HW_CACHE:
+               perf_evsel__hw_cache_name(evsel, bf, sizeof(bf));
+               break;
+
+       case PERF_TYPE_SOFTWARE:
+               perf_evsel__sw_name(evsel, bf, sizeof(bf));
                break;
+
+       case PERF_TYPE_TRACEPOINT:
+               scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint");
+               break;
+
+       case PERF_TYPE_BREAKPOINT:
+               perf_evsel__bp_name(evsel, bf, sizeof(bf));
+               break;
+
        default:
-               /*
-                * FIXME
-                *
-                * This is the minimal perf_evsel__name so that we can
-                * reconstruct event names taking into account event modifiers.
-                *
-                * The old event_name uses it now for raw anr hw events, so that
-                * we don't drag all the parsing stuff into the python binding.
-                *
-                * On the next devel cycle the rest of the event naming will be
-                * brought here.
-                */
-               return 0;
-       }
-
-       return ret;
+               scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
+               break;
+       }
+
+       evsel->name = strdup(bf);
+
+       return evsel->name ?: "unknown";
 }
 
 void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
index 4ba8b564e6f47f039652ebac739d9d899d5881f5..67cc5033d19234e28071523f51ecf7c7186822b1 100644 (file)
@@ -83,8 +83,19 @@ void perf_evsel__config(struct perf_evsel *evsel,
                        struct perf_record_opts *opts,
                        struct perf_evsel *first);
 
-const char* __perf_evsel__hw_name(u64 config);
-int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
+bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
+
+#define PERF_EVSEL__MAX_ALIASES 8
+
+extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
+                                      [PERF_EVSEL__MAX_ALIASES];
+extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
+                                         [PERF_EVSEL__MAX_ALIASES];
+const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
+                                      [PERF_EVSEL__MAX_ALIASES];
+int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
+                                           char *bf, size_t size);
+const char *perf_evsel__name(struct perf_evsel *evsel);
 
 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
index e909d43cf5422333e4d47d2b412c1f3fa0b636af..5a47aba46759274f7f542e533bae4a62749d565a 100644 (file)
@@ -641,7 +641,7 @@ static int write_event_desc(int fd, struct perf_header *h __used,
                /*
                 * write event string as passed on cmdline
                 */
-               ret = do_write_string(fd, event_name(attr));
+               ret = do_write_string(fd, perf_evsel__name(attr));
                if (ret < 0)
                        return ret;
                /*
@@ -1474,15 +1474,15 @@ out:
 
 static int process_tracing_data(struct perf_file_section *section __unused,
                              struct perf_header *ph __unused,
-                             int feat __unused, int fd)
+                             int feat __unused, int fd, void *data)
 {
-       trace_report(fd, false);
+       trace_report(fd, data, false);
        return 0;
 }
 
 static int process_build_id(struct perf_file_section *section,
                            struct perf_header *ph,
-                           int feat __unused, int fd)
+                           int feat __unused, int fd, void *data __used)
 {
        if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
                pr_debug("Failed to read buildids, continuing...\n");
@@ -1493,7 +1493,7 @@ struct feature_ops {
        int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
        void (*print)(struct perf_header *h, int fd, FILE *fp);
        int (*process)(struct perf_file_section *section,
-                      struct perf_header *h, int feat, int fd);
+                      struct perf_header *h, int feat, int fd, void *data);
        const char *name;
        bool full_only;
 };
@@ -1988,7 +1988,7 @@ int perf_file_header__read(struct perf_file_header *header,
 
 static int perf_file_section__process(struct perf_file_section *section,
                                      struct perf_header *ph,
-                                     int feat, int fd, void *data __used)
+                                     int feat, int fd, void *data)
 {
        if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
                pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -2004,7 +2004,7 @@ static int perf_file_section__process(struct perf_file_section *section,
        if (!feat_ops[feat].process)
                return 0;
 
-       return feat_ops[feat].process(section, ph, feat, fd);
+       return feat_ops[feat].process(section, ph, feat, fd, data);
 }
 
 static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
@@ -2093,9 +2093,11 @@ static int read_attr(int fd, struct perf_header *ph,
        return ret <= 0 ? -1 : 0;
 }
 
-static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel)
+static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel,
+                                          struct pevent *pevent)
 {
-       struct event_format *event = trace_find_event(evsel->attr.config);
+       struct event_format *event = pevent_find_event(pevent,
+                                                      evsel->attr.config);
        char bf[128];
 
        if (event == NULL)
@@ -2109,13 +2111,14 @@ static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel)
        return 0;
 }
 
-static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist)
+static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist,
+                                            struct pevent *pevent)
 {
        struct perf_evsel *pos;
 
        list_for_each_entry(pos, &evlist->entries, node) {
                if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
-                   perf_evsel__set_tracepoint_name(pos))
+                   perf_evsel__set_tracepoint_name(pos, pevent))
                        return -1;
        }
 
@@ -2198,12 +2201,12 @@ int perf_session__read_header(struct perf_session *session, int fd)
                event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
        }
 
-       perf_header__process_sections(header, fd, NULL,
+       perf_header__process_sections(header, fd, &session->pevent,
                                      perf_file_section__process);
 
        lseek(fd, header->data_offset, SEEK_SET);
 
-       if (perf_evlist__set_tracepoint_names(session->evlist))
+       if (perf_evlist__set_tracepoint_names(session->evlist, session->pevent))
                goto out_delete_evlist;
 
        header->frozen = 1;
@@ -2419,8 +2422,8 @@ int perf_event__process_tracing_data(union perf_event *event,
        lseek(session->fd, offset + sizeof(struct tracing_data_event),
              SEEK_SET);
 
-       size_read = trace_report(session->fd, session->repipe);
-
+       size_read = trace_report(session->fd, &session->pevent,
+                                session->repipe);
        padding = ALIGN(size_read, sizeof(u64)) - size_read;
 
        if (read(session->fd, buf, padding) < 0)
index 34bb556d62191a1300b295011be6210f9633fcf7..0b096c27a419bb46969e75fe8590f65dbde149be 100644 (file)
@@ -47,6 +47,7 @@ enum hist_column {
        HISTC_SYMBOL_TO,
        HISTC_DSO_FROM,
        HISTC_DSO_TO,
+       HISTC_SRCLINE,
        HISTC_NR_COLS, /* Last entry */
 };
 
index 1eb804fd3fbff078baa9e70f57d850676607c1b9..b6842c1d02a8dfd6ed22da698e8e3cf65ff9a50c 100644 (file)
@@ -108,4 +108,14 @@ int eprintf(int level,
 #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
 
+/*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+
 #endif
index 35ae56864e4f59625369941886b196438f107c99..a1f4e3669142630aa641d1a34b0f53673b6b67b0 100644 (file)
@@ -669,25 +669,26 @@ struct machine *machines__find(struct rb_root *self, pid_t pid)
 struct machine *machines__findnew(struct rb_root *self, pid_t pid)
 {
        char path[PATH_MAX];
-       const char *root_dir;
+       const char *root_dir = "";
        struct machine *machine = machines__find(self, pid);
 
-       if (!machine || machine->pid != pid) {
-               if (pid == HOST_KERNEL_ID || pid == DEFAULT_GUEST_KERNEL_ID)
-                       root_dir = "";
-               else {
-                       if (!symbol_conf.guestmount)
-                               goto out;
-                       sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
-                       if (access(path, R_OK)) {
-                               pr_err("Can't access file %s\n", path);
-                               goto out;
-                       }
-                       root_dir = path;
+       if (machine && (machine->pid == pid))
+               goto out;
+
+       if ((pid != HOST_KERNEL_ID) &&
+           (pid != DEFAULT_GUEST_KERNEL_ID) &&
+           (symbol_conf.guestmount)) {
+               sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
+               if (access(path, R_OK)) {
+                       pr_err("Can't access file %s\n", path);
+                       machine = NULL;
+                       goto out;
                }
-               machine = machines__add(self, pid, root_dir);
+               root_dir = path;
        }
 
+       machine = machines__add(self, pid, root_dir);
+
 out:
        return machine;
 }
index 81371bad4ef0e43e1121b5b8c4367fe4d6b212d8..c14c665d9a259c8c5c9aed791a32f2096eff6bb0 100644 (file)
@@ -157,7 +157,7 @@ void machine__exit(struct machine *self);
 void machine__delete(struct machine *self);
 
 int machine__resolve_callchain(struct machine *machine,
-                              struct perf_evsel *evsel, struct thread *thread,
+                              struct thread *thread,
                               struct ip_callchain *chain,
                               struct symbol **parent);
 int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
index 76b98e2a587d7c8a52a1264d88aad3bdb6839831..1b997d2b89ce2638f63c01aee63c2b7884028427 100644 (file)
@@ -181,6 +181,22 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
        return 0;
 }
 
+static int test__checkevent_breakpoint_rw(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong type",
+                       PERF_TYPE_BREAKPOINT == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong bp_type",
+               (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->attr.bp_type);
+       TEST_ASSERT_VAL("wrong bp_len",
+                       HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+       return 0;
+}
+
 static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
 {
        struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -309,6 +325,8 @@ static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
        TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong name",
+                       !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:u"));
 
        return test__checkevent_breakpoint(evlist);
 }
@@ -322,6 +340,8 @@ static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
        TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong name",
+                       !strcmp(perf_evsel__name(evsel), "mem:0x0:x:k"));
 
        return test__checkevent_breakpoint_x(evlist);
 }
@@ -335,6 +355,8 @@ static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
        TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
        TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong name",
+                       !strcmp(perf_evsel__name(evsel), "mem:0x0:r:hp"));
 
        return test__checkevent_breakpoint_r(evlist);
 }
@@ -348,10 +370,27 @@ static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
        TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
        TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong name",
+                       !strcmp(perf_evsel__name(evsel), "mem:0x0:w:up"));
 
        return test__checkevent_breakpoint_w(evlist);
 }
 
+static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel = list_entry(evlist->entries.next,
+                                             struct perf_evsel, node);
+
+       TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong name",
+                       !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:kp"));
+
+       return test__checkevent_breakpoint_rw(evlist);
+}
+
 static int test__checkevent_pmu(struct perf_evlist *evlist)
 {
 
@@ -413,19 +452,63 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
 {
        struct perf_evsel *evsel;
 
-       /* cpu/config=1,name=krava1/u */
+       /* cpu/config=1,name=krava/u */
        evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
        TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
        TEST_ASSERT_VAL("wrong config",  1 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+       TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava"));
 
-       /* cpu/config=2/" */
+       /* cpu/config=2/u" */
        evsel = list_entry(evsel->node.next, struct perf_evsel, node);
        TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
        TEST_ASSERT_VAL("wrong config",  2 == evsel->attr.config);
-       TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
+       TEST_ASSERT_VAL("wrong name",
+                       !strcmp(perf_evsel__name(evsel), "raw 0x2:u"));
+
+       return 0;
+}
+
+static int test__checkterms_simple(struct list_head *terms)
+{
+       struct parse_events__term *term;
+
+       /* config=10 */
+       term = list_entry(terms->next, struct parse_events__term, list);
+       TEST_ASSERT_VAL("wrong type term",
+                       term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
+       TEST_ASSERT_VAL("wrong type val",
+                       term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+       TEST_ASSERT_VAL("wrong val", term->val.num == 10);
+       TEST_ASSERT_VAL("wrong config", !term->config);
+
+       /* config1 */
+       term = list_entry(term->list.next, struct parse_events__term, list);
+       TEST_ASSERT_VAL("wrong type term",
+                       term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
+       TEST_ASSERT_VAL("wrong type val",
+                       term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+       TEST_ASSERT_VAL("wrong val", term->val.num == 1);
+       TEST_ASSERT_VAL("wrong config", !term->config);
+
+       /* config2=3 */
+       term = list_entry(term->list.next, struct parse_events__term, list);
+       TEST_ASSERT_VAL("wrong type term",
+                       term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
+       TEST_ASSERT_VAL("wrong type val",
+                       term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+       TEST_ASSERT_VAL("wrong val", term->val.num == 3);
+       TEST_ASSERT_VAL("wrong config", !term->config);
+
+       /* umask=1*/
+       term = list_entry(term->list.next, struct parse_events__term, list);
+       TEST_ASSERT_VAL("wrong type term",
+                       term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
+       TEST_ASSERT_VAL("wrong type val",
+                       term->type_val == PARSE_EVENTS__TERM_TYPE_NUM);
+       TEST_ASSERT_VAL("wrong val", term->val.num == 1);
+       TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask"));
 
        return 0;
 }
@@ -541,10 +624,16 @@ static struct test__event_st test__events[] = {
                .name  = "instructions:H",
                .check = test__checkevent_exclude_guest_modifier,
        },
+       [26] = {
+               .name  = "mem:0:rw",
+               .check = test__checkevent_breakpoint_rw,
+       },
+       [27] = {
+               .name  = "mem:0:rw:kp",
+               .check = test__checkevent_breakpoint_rw_modifier,
+       },
 };
 
-#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
-
 static struct test__event_st test__events_pmu[] = {
        [0] = {
                .name  = "cpu/config=10,config1,config2=3,period=1000/u",
@@ -556,10 +645,23 @@ static struct test__event_st test__events_pmu[] = {
        },
 };
 
-#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
-                             sizeof(struct test__event_st))
+struct test__term {
+       const char *str;
+       __u32 type;
+       int (*check)(struct list_head *terms);
+};
+
+static struct test__term test__terms[] = {
+       [0] = {
+               .str   = "config=10,config1,config2=3,umask=1",
+               .check = test__checkterms_simple,
+       },
+};
+
+#define TEST__TERMS_CNT (sizeof(test__terms) / \
+                        sizeof(struct test__term))
 
-static int test(struct test__event_st *e)
+static int test_event(struct test__event_st *e)
 {
        struct perf_evlist *evlist;
        int ret;
@@ -590,7 +692,48 @@ static int test_events(struct test__event_st *events, unsigned cnt)
                struct test__event_st *e = &events[i];
 
                pr_debug("running test %d '%s'\n", i, e->name);
-               ret = test(e);
+               ret = test_event(e);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int test_term(struct test__term *t)
+{
+       struct list_head *terms;
+       int ret;
+
+       terms = malloc(sizeof(*terms));
+       if (!terms)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(terms);
+
+       ret = parse_events_terms(terms, t->str);
+       if (ret) {
+               pr_debug("failed to parse terms '%s', err %d\n",
+                        t->str , ret);
+               return ret;
+       }
+
+       ret = t->check(terms);
+       parse_events__free_terms(terms);
+
+       return ret;
+}
+
+static int test_terms(struct test__term *terms, unsigned cnt)
+{
+       int ret = 0;
+       unsigned i;
+
+       for (i = 0; i < cnt; i++) {
+               struct test__term *t = &terms[i];
+
+               pr_debug("running test %d '%s'\n", i, t->str);
+               ret = test_term(t);
                if (ret)
                        break;
        }
@@ -617,9 +760,17 @@ int parse_events__test(void)
 {
        int ret;
 
-       ret = test_events(test__events, TEST__EVENTS_CNT);
-       if (!ret && test_pmu())
-               ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
+#define TEST_EVENTS(tests)                             \
+do {                                                   \
+       ret = test_events(tests, ARRAY_SIZE(tests));    \
+       if (ret)                                        \
+               return ret;                             \
+} while (0)
 
-       return ret;
+       TEST_EVENTS(test__events);
+
+       if (test_pmu())
+               TEST_EVENTS(test__events_pmu);
+
+       return test_terms(test__terms, ARRAY_SIZE(test__terms));
 }
index 05dbc8b3c767217ceb3204c7be46f5aedbb205c4..1aa721d7c10f33d84bbd63f8761ed67f18fbe86c 100644 (file)
 #include "cache.h"
 #include "header.h"
 #include "debugfs.h"
+#include "parse-events-bison.h"
+#define YY_EXTRA_TYPE int
 #include "parse-events-flex.h"
 #include "pmu.h"
 
 #define MAX_NAME_LEN 100
 
 struct event_symbol {
-       u8              type;
-       u64             config;
        const char      *symbol;
        const char      *alias;
 };
@@ -26,32 +26,88 @@ struct event_symbol {
 #ifdef PARSER_DEBUG
 extern int parse_events_debug;
 #endif
-int parse_events_parse(struct list_head *list, int *idx);
-
-#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
-#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
-
-static struct event_symbol event_symbols[] = {
-  { CHW(CPU_CYCLES),                   "cpu-cycles",                   "cycles"                },
-  { CHW(STALLED_CYCLES_FRONTEND),      "stalled-cycles-frontend",      "idle-cycles-frontend"  },
-  { CHW(STALLED_CYCLES_BACKEND),       "stalled-cycles-backend",       "idle-cycles-backend"   },
-  { CHW(INSTRUCTIONS),                 "instructions",                 ""                      },
-  { CHW(CACHE_REFERENCES),             "cache-references",             ""                      },
-  { CHW(CACHE_MISSES),                 "cache-misses",                 ""                      },
-  { CHW(BRANCH_INSTRUCTIONS),          "branch-instructions",          "branches"              },
-  { CHW(BRANCH_MISSES),                        "branch-misses",                ""                      },
-  { CHW(BUS_CYCLES),                   "bus-cycles",                   ""                      },
-  { CHW(REF_CPU_CYCLES),               "ref-cycles",                   ""                      },
-
-  { CSW(CPU_CLOCK),                    "cpu-clock",                    ""                      },
-  { CSW(TASK_CLOCK),                   "task-clock",                   ""                      },
-  { CSW(PAGE_FAULTS),                  "page-faults",                  "faults"                },
-  { CSW(PAGE_FAULTS_MIN),              "minor-faults",                 ""                      },
-  { CSW(PAGE_FAULTS_MAJ),              "major-faults",                 ""                      },
-  { CSW(CONTEXT_SWITCHES),             "context-switches",             "cs"                    },
-  { CSW(CPU_MIGRATIONS),               "cpu-migrations",               "migrations"            },
-  { CSW(ALIGNMENT_FAULTS),             "alignment-faults",             ""                      },
-  { CSW(EMULATION_FAULTS),             "emulation-faults",             ""                      },
+int parse_events_parse(void *data, void *scanner);
+
+static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
+       [PERF_COUNT_HW_CPU_CYCLES] = {
+               .symbol = "cpu-cycles",
+               .alias  = "cycles",
+       },
+       [PERF_COUNT_HW_INSTRUCTIONS] = {
+               .symbol = "instructions",
+               .alias  = "",
+       },
+       [PERF_COUNT_HW_CACHE_REFERENCES] = {
+               .symbol = "cache-references",
+               .alias  = "",
+       },
+       [PERF_COUNT_HW_CACHE_MISSES] = {
+               .symbol = "cache-misses",
+               .alias  = "",
+       },
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = {
+               .symbol = "branch-instructions",
+               .alias  = "branches",
+       },
+       [PERF_COUNT_HW_BRANCH_MISSES] = {
+               .symbol = "branch-misses",
+               .alias  = "",
+       },
+       [PERF_COUNT_HW_BUS_CYCLES] = {
+               .symbol = "bus-cycles",
+               .alias  = "",
+       },
+       [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = {
+               .symbol = "stalled-cycles-frontend",
+               .alias  = "idle-cycles-frontend",
+       },
+       [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = {
+               .symbol = "stalled-cycles-backend",
+               .alias  = "idle-cycles-backend",
+       },
+       [PERF_COUNT_HW_REF_CPU_CYCLES] = {
+               .symbol = "ref-cycles",
+               .alias  = "",
+       },
+};
+
+static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
+       [PERF_COUNT_SW_CPU_CLOCK] = {
+               .symbol = "cpu-clock",
+               .alias  = "",
+       },
+       [PERF_COUNT_SW_TASK_CLOCK] = {
+               .symbol = "task-clock",
+               .alias  = "",
+       },
+       [PERF_COUNT_SW_PAGE_FAULTS] = {
+               .symbol = "page-faults",
+               .alias  = "faults",
+       },
+       [PERF_COUNT_SW_CONTEXT_SWITCHES] = {
+               .symbol = "context-switches",
+               .alias  = "cs",
+       },
+       [PERF_COUNT_SW_CPU_MIGRATIONS] = {
+               .symbol = "cpu-migrations",
+               .alias  = "migrations",
+       },
+       [PERF_COUNT_SW_PAGE_FAULTS_MIN] = {
+               .symbol = "minor-faults",
+               .alias  = "",
+       },
+       [PERF_COUNT_SW_PAGE_FAULTS_MAJ] = {
+               .symbol = "major-faults",
+               .alias  = "",
+       },
+       [PERF_COUNT_SW_ALIGNMENT_FAULTS] = {
+               .symbol = "alignment-faults",
+               .alias  = "",
+       },
+       [PERF_COUNT_SW_EMULATION_FAULTS] = {
+               .symbol = "emulation-faults",
+               .alias  = "",
+       },
 };
 
 #define __PERF_EVENT_FIELD(config, name) \
@@ -62,63 +118,6 @@ static struct event_symbol event_symbols[] = {
 #define PERF_EVENT_TYPE(config)                __PERF_EVENT_FIELD(config, TYPE)
 #define PERF_EVENT_ID(config)          __PERF_EVENT_FIELD(config, EVENT)
 
-static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
-       "cpu-clock",
-       "task-clock",
-       "page-faults",
-       "context-switches",
-       "CPU-migrations",
-       "minor-faults",
-       "major-faults",
-       "alignment-faults",
-       "emulation-faults",
-};
-
-#define MAX_ALIASES 8
-
-static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = {
- { "L1-dcache",        "l1-d",         "l1d",          "L1-data",              },
- { "L1-icache",        "l1-i",         "l1i",          "L1-instruction",       },
- { "LLC",      "L2",                                                   },
- { "dTLB",     "d-tlb",        "Data-TLB",                             },
- { "iTLB",     "i-tlb",        "Instruction-TLB",                      },
- { "branch",   "branches",     "bpu",          "btb",          "bpc",  },
- { "node",                                                             },
-};
-
-static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = {
- { "load",     "loads",        "read",                                 },
- { "store",    "stores",       "write",                                },
- { "prefetch", "prefetches",   "speculative-read", "speculative-load", },
-};
-
-static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
-                                 [MAX_ALIASES] = {
- { "refs",     "Reference",    "ops",          "access",               },
- { "misses",   "miss",                                                 },
-};
-
-#define C(x)           PERF_COUNT_HW_CACHE_##x
-#define CACHE_READ     (1 << C(OP_READ))
-#define CACHE_WRITE    (1 << C(OP_WRITE))
-#define CACHE_PREFETCH (1 << C(OP_PREFETCH))
-#define COP(x)         (1 << x)
-
-/*
- * cache operartion stat
- * L1I : Read and prefetch only
- * ITLB and BPU : Read-only
- */
-static unsigned long hw_cache_stat[C(MAX)] = {
- [C(L1D)]      = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(L1I)]      = (CACHE_READ | CACHE_PREFETCH),
- [C(LL)]       = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(DTLB)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
- [C(ITLB)]     = (CACHE_READ),
- [C(BPU)]      = (CACHE_READ),
- [C(NODE)]     = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
-};
-
 #define for_each_subsystem(sys_dir, sys_dirent, sys_next)             \
        while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next)        \
        if (sys_dirent.d_type == DT_DIR &&                                     \
@@ -218,48 +217,6 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
        return NULL;
 }
 
-#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
-static const char *tracepoint_id_to_name(u64 config)
-{
-       static char buf[TP_PATH_LEN];
-       struct tracepoint_path *path;
-
-       path = tracepoint_id_to_path(config);
-       if (path) {
-               snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
-               free(path->name);
-               free(path->system);
-               free(path);
-       } else
-               snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
-
-       return buf;
-}
-
-static int is_cache_op_valid(u8 cache_type, u8 cache_op)
-{
-       if (hw_cache_stat[cache_type] & COP(cache_op))
-               return 1;       /* valid */
-       else
-               return 0;       /* invalid */
-}
-
-static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
-{
-       static char name[50];
-
-       if (cache_result) {
-               sprintf(name, "%s-%s-%s", hw_cache[cache_type][0],
-                       hw_cache_op[cache_op][0],
-                       hw_cache_result[cache_result][0]);
-       } else {
-               sprintf(name, "%s-%s", hw_cache[cache_type][0],
-                       hw_cache_op[cache_op][1]);
-       }
-
-       return name;
-}
-
 const char *event_type(int type)
 {
        switch (type) {
@@ -282,76 +239,6 @@ const char *event_type(int type)
        return "unknown";
 }
 
-const char *event_name(struct perf_evsel *evsel)
-{
-       u64 config = evsel->attr.config;
-       int type = evsel->attr.type;
-
-       if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
-               /*
-                * XXX minimal fix, see comment on perf_evsen__name, this static buffer
-                * will go away together with event_name in the next devel cycle.
-                */
-               static char bf[128];
-               perf_evsel__name(evsel, bf, sizeof(bf));
-               return bf;
-       }
-
-       if (evsel->name)
-               return evsel->name;
-
-       return __event_name(type, config);
-}
-
-const char *__event_name(int type, u64 config)
-{
-       static char buf[32];
-
-       if (type == PERF_TYPE_RAW) {
-               sprintf(buf, "raw 0x%" PRIx64, config);
-               return buf;
-       }
-
-       switch (type) {
-       case PERF_TYPE_HARDWARE:
-               return __perf_evsel__hw_name(config);
-
-       case PERF_TYPE_HW_CACHE: {
-               u8 cache_type, cache_op, cache_result;
-
-               cache_type   = (config >>  0) & 0xff;
-               if (cache_type > PERF_COUNT_HW_CACHE_MAX)
-                       return "unknown-ext-hardware-cache-type";
-
-               cache_op     = (config >>  8) & 0xff;
-               if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX)
-                       return "unknown-ext-hardware-cache-op";
-
-               cache_result = (config >> 16) & 0xff;
-               if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX)
-                       return "unknown-ext-hardware-cache-result";
-
-               if (!is_cache_op_valid(cache_type, cache_op))
-                       return "invalid-cache";
-
-               return event_cache_name(cache_type, cache_op, cache_result);
-       }
-
-       case PERF_TYPE_SOFTWARE:
-               if (config < PERF_COUNT_SW_MAX && sw_event_names[config])
-                       return sw_event_names[config];
-               return "unknown-software";
-
-       case PERF_TYPE_TRACEPOINT:
-               return tracepoint_id_to_name(config);
-
-       default:
-               break;
-       }
-
-       return "unknown";
-}
-
 static int add_event(struct list_head **_list, int *idx,
                     struct perf_event_attr *attr, char *name)
 {
@@ -373,19 +260,20 @@ static int add_event(struct list_head **_list, int *idx,
                return -ENOMEM;
        }
 
-       evsel->name = strdup(name);
+       if (name)
+               evsel->name = strdup(name);
        list_add_tail(&evsel->node, list);
        *_list = list;
        return 0;
 }
 
-static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
+static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
 {
        int i, j;
        int n, longest = -1;
 
        for (i = 0; i < size; i++) {
-               for (j = 0; j < MAX_ALIASES && names[i][j]; j++) {
+               for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) {
                        n = strlen(names[i][j]);
                        if (n > longest && !strncasecmp(str, names[i][j], n))
                                longest = n;
@@ -410,7 +298,7 @@ int parse_events_add_cache(struct list_head **list, int *idx,
         * No fallback - if we cannot get a clear cache type
         * then bail out:
         */
-       cache_type = parse_aliases(type, hw_cache,
+       cache_type = parse_aliases(type, perf_evsel__hw_cache,
                                   PERF_COUNT_HW_CACHE_MAX);
        if (cache_type == -1)
                return -EINVAL;
@@ -423,18 +311,18 @@ int parse_events_add_cache(struct list_head **list, int *idx,
                snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str);
 
                if (cache_op == -1) {
-                       cache_op = parse_aliases(str, hw_cache_op,
+                       cache_op = parse_aliases(str, perf_evsel__hw_cache_op,
                                                 PERF_COUNT_HW_CACHE_OP_MAX);
                        if (cache_op >= 0) {
-                               if (!is_cache_op_valid(cache_type, cache_op))
+                               if (!perf_evsel__is_cache_op_valid(cache_type, cache_op))
                                        return -EINVAL;
                                continue;
                        }
                }
 
                if (cache_result == -1) {
-                       cache_result = parse_aliases(str, hw_cache_result,
-                                               PERF_COUNT_HW_CACHE_RESULT_MAX);
+                       cache_result = parse_aliases(str, perf_evsel__hw_cache_result,
+                                                    PERF_COUNT_HW_CACHE_RESULT_MAX);
                        if (cache_result >= 0)
                                continue;
                }
@@ -549,21 +437,31 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
                if (!type || !type[i])
                        break;
 
+#define CHECK_SET_TYPE(bit)            \
+do {                                   \
+       if (attr->bp_type & bit)        \
+               return -EINVAL;         \
+       else                            \
+               attr->bp_type |= bit;   \
+} while (0)
+
                switch (type[i]) {
                case 'r':
-                       attr->bp_type |= HW_BREAKPOINT_R;
+                       CHECK_SET_TYPE(HW_BREAKPOINT_R);
                        break;
                case 'w':
-                       attr->bp_type |= HW_BREAKPOINT_W;
+                       CHECK_SET_TYPE(HW_BREAKPOINT_W);
                        break;
                case 'x':
-                       attr->bp_type |= HW_BREAKPOINT_X;
+                       CHECK_SET_TYPE(HW_BREAKPOINT_X);
                        break;
                default:
                        return -EINVAL;
                }
        }
 
+#undef CHECK_SET_TYPE
+
        if (!attr->bp_type) /* Default */
                attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
 
@@ -574,7 +472,6 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
                                void *ptr, char *type)
 {
        struct perf_event_attr attr;
-       char name[MAX_NAME_LEN];
 
        memset(&attr, 0, sizeof(attr));
        attr.bp_addr = (unsigned long) ptr;
@@ -593,8 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
 
        attr.type = PERF_TYPE_BREAKPOINT;
 
-       snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw");
-       return add_event(list, idx, &attr, name);
+       return add_event(list, idx, &attr, NULL);
 }
 
 static int config_term(struct perf_event_attr *attr,
@@ -666,8 +562,7 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
            config_attr(&attr, head_config, 1))
                return -EINVAL;
 
-       return add_event(list, idx, &attr,
-                        (char *) __event_name(type, config));
+       return add_event(list, idx, &attr, NULL);
 }
 
 static int parse_events__is_name_term(struct parse_events__term *term)
@@ -675,8 +570,7 @@ static int parse_events__is_name_term(struct parse_events__term *term)
        return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
 }
 
-static char *pmu_event_name(struct perf_event_attr *attr,
-                           struct list_head *head_terms)
+static char *pmu_event_name(struct list_head *head_terms)
 {
        struct parse_events__term *term;
 
@@ -684,7 +578,7 @@ static char *pmu_event_name(struct perf_event_attr *attr,
                if (parse_events__is_name_term(term))
                        return term->val.str;
 
-       return (char *) __event_name(PERF_TYPE_RAW, attr->config);
+       return NULL;
 }
 
 int parse_events_add_pmu(struct list_head **list, int *idx,
@@ -699,6 +593,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
 
        memset(&attr, 0, sizeof(attr));
 
+       if (perf_pmu__check_alias(pmu, head_config))
+               return -EINVAL;
+
        /*
         * Configure hardcoded terms first, no need to check
         * return value when called with fail == 0 ;)
@@ -709,7 +606,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
                return -EINVAL;
 
        return add_event(list, idx, &attr,
-                        pmu_event_name(&attr, head_config));
+                        pmu_event_name(head_config));
 }
 
 void parse_events_update_lists(struct list_head *list_event,
@@ -787,27 +684,62 @@ int parse_events_modifier(struct list_head *list, char *str)
        return 0;
 }
 
-int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
+static int parse_events__scanner(const char *str, void *data, int start_token)
 {
-       LIST_HEAD(list);
-       LIST_HEAD(list_tmp);
        YY_BUFFER_STATE buffer;
-       int ret, idx = evlist->nr_entries;
+       void *scanner;
+       int ret;
+
+       ret = parse_events_lex_init_extra(start_token, &scanner);
+       if (ret)
+               return ret;
 
-       buffer = parse_events__scan_string(str);
+       buffer = parse_events__scan_string(str, scanner);
 
 #ifdef PARSER_DEBUG
        parse_events_debug = 1;
 #endif
-       ret = parse_events_parse(&list, &idx);
+       ret = parse_events_parse(data, scanner);
 
-       parse_events__flush_buffer(buffer);
-       parse_events__delete_buffer(buffer);
-       parse_events_lex_destroy();
+       parse_events__flush_buffer(buffer, scanner);
+       parse_events__delete_buffer(buffer, scanner);
+       parse_events_lex_destroy(scanner);
+       return ret;
+}
+
+/*
+ * parse event config string, return a list of event terms.
+ */
+int parse_events_terms(struct list_head *terms, const char *str)
+{
+       struct parse_events_data__terms data = {
+               .terms = NULL,
+       };
+       int ret;
 
+       ret = parse_events__scanner(str, &data, PE_START_TERMS);
        if (!ret) {
-               int entries = idx - evlist->nr_entries;
-               perf_evlist__splice_list_tail(evlist, &list, entries);
+               list_splice(data.terms, terms);
+               free(data.terms);
+               return 0;
+       }
+
+       parse_events__free_terms(data.terms);
+       return ret;
+}
+
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
+{
+       struct parse_events_data__events data = {
+               .list = LIST_HEAD_INIT(data.list),
+               .idx  = evlist->nr_entries,
+       };
+       int ret;
+
+       ret = parse_events__scanner(str, &data, PE_START_EVENTS);
+       if (!ret) {
+               int entries = data.idx - evlist->nr_entries;
+               perf_evlist__splice_list_tail(evlist, &data.list, entries);
                return 0;
        }
 
@@ -946,16 +878,13 @@ int is_valid_tracepoint(const char *event_string)
        return 0;
 }
 
-void print_events_type(u8 type)
+static void __print_events_type(u8 type, struct event_symbol *syms,
+                               unsigned max)
 {
-       struct event_symbol *syms = event_symbols;
-       unsigned int i;
        char name[64];
+       unsigned i;
 
-       for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
-               if (type != syms->type)
-                       continue;
-
+       for (i = 0; i < max ; i++, syms++) {
                if (strlen(syms->alias))
                        snprintf(name, sizeof(name),  "%s OR %s",
                                 syms->symbol, syms->alias);
@@ -967,19 +896,28 @@ void print_events_type(u8 type)
        }
 }
 
+void print_events_type(u8 type)
+{
+       if (type == PERF_TYPE_SOFTWARE)
+               __print_events_type(type, event_symbols_sw, PERF_COUNT_SW_MAX);
+       else
+               __print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX);
+}
+
 int print_hwcache_events(const char *event_glob)
 {
        unsigned int type, op, i, printed = 0;
+       char name[64];
 
        for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
                for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
                        /* skip invalid cache type */
-                       if (!is_cache_op_valid(type, op))
+                       if (!perf_evsel__is_cache_op_valid(type, op))
                                continue;
 
                        for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
-                               char *name = event_cache_name(type, op, i);
-
+                               __perf_evsel__hw_cache_type_op_res_name(type, op, i,
+                                                                       name, sizeof(name));
                                if (event_glob != NULL && !strglobmatch(name, event_glob))
                                        continue;
 
@@ -993,26 +931,13 @@ int print_hwcache_events(const char *event_glob)
        return printed;
 }
 
-/*
- * Print the help text for the event symbols:
- */
-void print_events(const char *event_glob)
+static void print_symbol_events(const char *event_glob, unsigned type,
+                               struct event_symbol *syms, unsigned max)
 {
-       unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
-       struct event_symbol *syms = event_symbols;
+       unsigned i, printed = 0;
        char name[MAX_NAME_LEN];
 
-       printf("\n");
-       printf("List of pre-defined events (to be used in -e):\n");
-
-       for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
-               type = syms->type;
-
-               if (type != prev_type && printed) {
-                       printf("\n");
-                       printed = 0;
-                       ntypes_printed++;
-               }
+       for (i = 0; i < max; i++, syms++) {
 
                if (event_glob != NULL && 
                    !(strglobmatch(syms->symbol, event_glob) ||
@@ -1023,17 +948,31 @@ void print_events(const char *event_glob)
                        snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
                else
                        strncpy(name, syms->symbol, MAX_NAME_LEN);
-               printf("  %-50s [%s]\n", name,
-                       event_type_descriptors[type]);
 
-               prev_type = type;
-               ++printed;
+               printf("  %-50s [%s]\n", name, event_type_descriptors[type]);
+
+               printed++;
        }
 
-       if (ntypes_printed) {
-               printed = 0;
+       if (printed)
                printf("\n");
-       }
+}
+
+/*
+ * Print the help text for the event symbols:
+ */
+void print_events(const char *event_glob)
+{
+
+       printf("\n");
+       printf("List of pre-defined events (to be used in -e):\n");
+
+       print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
+                           event_symbols_hw, PERF_COUNT_HW_MAX);
+
+       print_symbol_events(event_glob, PERF_TYPE_SOFTWARE,
+                           event_symbols_sw, PERF_COUNT_SW_MAX);
+
        print_hwcache_events(event_glob);
 
        if (event_glob != NULL)
@@ -1106,6 +1045,13 @@ int parse_events__term_str(struct parse_events__term **term,
                        config, str, 0);
 }
 
+int parse_events__term_clone(struct parse_events__term **new,
+                            struct parse_events__term *term)
+{
+       return new_term(new, term->type_val, term->type_term, term->config,
+                       term->val.str, term->val.num);
+}
+
 void parse_events__free_terms(struct list_head *terms)
 {
        struct parse_events__term *term, *h;
index 8cac57ab4ee6b396549a4ee857486effedb9343b..ee9c218a193c8d8c8b20f893da976d262931e172 100644 (file)
@@ -26,13 +26,12 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
 extern bool have_tracepoints(struct list_head *evlist);
 
 const char *event_type(int type);
-const char *event_name(struct perf_evsel *event);
-extern const char *__event_name(int type, u64 config);
 
 extern int parse_events_option(const struct option *opt, const char *str,
                               int unset);
 extern int parse_events(struct perf_evlist *evlist, const char *str,
                        int unset);
+extern int parse_events_terms(struct list_head *terms, const char *str);
 extern int parse_filter(const struct option *opt, const char *str, int unset);
 
 #define EVENTS_HELP_MAX (128*1024)
@@ -63,11 +62,22 @@ struct parse_events__term {
        struct list_head list;
 };
 
+struct parse_events_data__events {
+       struct list_head list;
+       int idx;
+};
+
+struct parse_events_data__terms {
+       struct list_head *terms;
+};
+
 int parse_events__is_hardcoded_term(struct parse_events__term *term);
 int parse_events__term_num(struct parse_events__term **_term,
                           int type_term, char *config, long num);
 int parse_events__term_str(struct parse_events__term **_term,
                           int type_term, char *config, char *str);
+int parse_events__term_clone(struct parse_events__term **new,
+                            struct parse_events__term *term);
 void parse_events__free_terms(struct list_head *terms);
 int parse_events_modifier(struct list_head *list, char *str);
 int parse_events_add_tracepoint(struct list_head **list, int *idx,
@@ -83,8 +93,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
                         char *pmu , struct list_head *head_config);
 void parse_events_update_lists(struct list_head *list_event,
                               struct list_head *list_all);
-void parse_events_error(struct list_head *list_all,
-                       int *idx, char const *msg);
+void parse_events_error(void *data, void *scanner, char const *msg);
 int parse_events__test(void);
 
 void print_events(const char *event_glob);
index 618a8e7883995bbee72f4b90c6d5e55a012f05f1..384ca74c6b22d442ad74b23d70dd3598a4e7208a 100644 (file)
@@ -1,4 +1,6 @@
 
+%option reentrant
+%option bison-bridge
 %option prefix="parse_events_"
 %option stack
 
@@ -8,7 +10,10 @@
 #include "parse-events-bison.h"
 #include "parse-events.h"
 
-static int __value(char *str, int base, int token)
+char *parse_events_get_text(yyscan_t yyscanner);
+YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
+
+static int __value(YYSTYPE *yylval, char *str, int base, int token)
 {
        long num;
 
@@ -17,35 +22,48 @@ static int __value(char *str, int base, int token)
        if (errno)
                return PE_ERROR;
 
-       parse_events_lval.num = num;
+       yylval->num = num;
        return token;
 }
 
-static int value(int base)
+static int value(yyscan_t scanner, int base)
 {
-       return __value(parse_events_text, base, PE_VALUE);
+       YYSTYPE *yylval = parse_events_get_lval(scanner);
+       char *text = parse_events_get_text(scanner);
+
+       return __value(yylval, text, base, PE_VALUE);
 }
 
-static int raw(void)
+static int raw(yyscan_t scanner)
 {
-       return __value(parse_events_text + 1, 16, PE_RAW);
+       YYSTYPE *yylval = parse_events_get_lval(scanner);
+       char *text = parse_events_get_text(scanner);
+
+       return __value(yylval, text + 1, 16, PE_RAW);
 }
 
-static int str(int token)
+static int str(yyscan_t scanner, int token)
 {
-       parse_events_lval.str = strdup(parse_events_text);
+       YYSTYPE *yylval = parse_events_get_lval(scanner);
+       char *text = parse_events_get_text(scanner);
+
+       yylval->str = strdup(text);
        return token;
 }
 
-static int sym(int type, int config)
+static int sym(yyscan_t scanner, int type, int config)
 {
-       parse_events_lval.num = (type << 16) + config;
-       return PE_VALUE_SYM;
+       YYSTYPE *yylval = parse_events_get_lval(scanner);
+
+       yylval->num = (type << 16) + config;
+       return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW;
 }
 
-static int term(int type)
+static int term(yyscan_t scanner, int type)
 {
-       parse_events_lval.num = type;
+       YYSTYPE *yylval = parse_events_get_lval(scanner);
+
+       yylval->num = type;
        return PE_TERM;
 }
 
@@ -58,28 +76,41 @@ num_hex             0x[a-fA-F0-9]+
 num_raw_hex    [a-fA-F0-9]+
 name           [a-zA-Z_*?][a-zA-Z0-9_*?]*
 modifier_event [ukhpGH]{1,8}
-modifier_bp    [rwx]
+modifier_bp    [rwx]{1,3}
 
 %%
-cpu-cycles|cycles                              { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
-stalled-cycles-frontend|idle-cycles-frontend   { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
-stalled-cycles-backend|idle-cycles-backend     { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
-instructions                                   { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
-cache-references                               { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
-cache-misses                                   { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
-branch-instructions|branches                   { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
-branch-misses                                  { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
-bus-cycles                                     { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
-ref-cycles                                     { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
-cpu-clock                                      { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
-task-clock                                     { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
-page-faults|faults                             { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
-minor-faults                                   { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
-major-faults                                   { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
-context-switches|cs                            { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
-cpu-migrations|migrations                      { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
-alignment-faults                               { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
-emulation-faults                               { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+
+%{
+       {
+               int start_token;
+
+               start_token = (int) parse_events_get_extra(yyscanner);
+               if (start_token) {
+                       parse_events_set_extra(NULL, yyscanner);
+                       return start_token;
+               }
+         }
+%}
+
+cpu-cycles|cycles                              { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend     { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions                                   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references                               { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses                                   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches                   { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses                                  { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles                                     { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles                                     { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-clock                                      { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock                                     { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults                             { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults                                   { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults                                   { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs                            { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations                      { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
 
 L1-dcache|l1-d|l1d|L1-data             |
 L1-icache|l1-i|l1i|L1-instruction      |
@@ -87,14 +118,14 @@ LLC|L2                                     |
 dTLB|d-tlb|Data-TLB                    |
 iTLB|i-tlb|Instruction-TLB             |
 branch|branches|bpu|btb|bpc            |
-node                                   { return str(PE_NAME_CACHE_TYPE); }
+node                                   { return str(yyscanner, PE_NAME_CACHE_TYPE); }
 
 load|loads|read                                |
 store|stores|write                     |
 prefetch|prefetches                    |
 speculative-read|speculative-load      |
 refs|Reference|ops|access              |
-misses|miss                            { return str(PE_NAME_CACHE_OP_RESULT); }
+misses|miss                            { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }
 
        /*
         * These are event config hardcoded term names to be specified
@@ -102,38 +133,39 @@ misses|miss                               { return str(PE_NAME_CACHE_OP_RESULT); }
         * so we can put them here directly. In case the we have a conflict
         * in future, this needs to go into '//' condition block.
         */
-config                 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
-config1                        { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
-config2                        { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
-name                   { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
-period                 { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
-branch_type            { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+config                 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
+config1                        { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
+config2                        { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+name                   { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
+period                 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
+branch_type            { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
 
 mem:                   { BEGIN(mem); return PE_PREFIX_MEM; }
-r{num_raw_hex}         { return raw(); }
-{num_dec}              { return value(10); }
-{num_hex}              { return value(16); }
+r{num_raw_hex}         { return raw(yyscanner); }
+{num_dec}              { return value(yyscanner, 10); }
+{num_hex}              { return value(yyscanner, 16); }
 
-{modifier_event}       { return str(PE_MODIFIER_EVENT); }
-{name}                 { return str(PE_NAME); }
+{modifier_event}       { return str(yyscanner, PE_MODIFIER_EVENT); }
+{name}                 { return str(yyscanner, PE_NAME); }
 "/"                    { return '/'; }
 -                      { return '-'; }
 ,                      { return ','; }
 :                      { return ':'; }
 =                      { return '='; }
+\n                     { }
 
 <mem>{
-{modifier_bp}          { return str(PE_MODIFIER_BP); }
+{modifier_bp}          { return str(yyscanner, PE_MODIFIER_BP); }
 :                      { return ':'; }
-{num_dec}              { return value(10); }
-{num_hex}              { return value(16); }
+{num_dec}              { return value(yyscanner, 10); }
+{num_hex}              { return value(yyscanner, 16); }
        /*
         * We need to separate 'mem:' scanner part, in order to get specific
         * modifier bits parsed out. Otherwise we would need to handle PE_NAME
         * and we'd need to parse it manually. During the escape from <mem>
         * state we need to put the escaping char back, so we dont miss it.
         */
-.                      { unput(*parse_events_text); BEGIN(INITIAL); }
+.                      { unput(*yytext); BEGIN(INITIAL); }
        /*
         * We destroy the scanner after reaching EOF,
         * but anyway just to be sure get back to INIT state.
@@ -143,7 +175,7 @@ r{num_raw_hex}              { return raw(); }
 
 %%
 
-int parse_events_wrap(void)
+int parse_events_wrap(void *scanner __used)
 {
        return 1;
 }
index 362cc59332ae78e0774fed92e3f20a2f751fa211..2bc5fbff2b5d2b101ac4b65cb9623c5d7ff24326 100644 (file)
@@ -1,7 +1,8 @@
-
+%pure-parser
 %name-prefix "parse_events_"
-%parse-param {struct list_head *list_all}
-%parse-param {int *idx}
+%parse-param {void *_data}
+%parse-param {void *scanner}
+%lex-param {void* scanner}
 
 %{
 
@@ -12,8 +13,9 @@
 #include "types.h"
 #include "util.h"
 #include "parse-events.h"
+#include "parse-events-bison.h"
 
-extern int parse_events_lex (void);
+extern int parse_events_lex (YYSTYPE* lvalp, void* scanner);
 
 #define ABORT_ON(val) \
 do { \
@@ -23,14 +25,16 @@ do { \
 
 %}
 
-%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
+%token PE_START_EVENTS PE_START_TERMS
+%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
 %token PE_NAME
 %token PE_MODIFIER_EVENT PE_MODIFIER_BP
 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
 %token PE_PREFIX_MEM PE_PREFIX_RAW
 %token PE_ERROR
 %type <num> PE_VALUE
-%type <num> PE_VALUE_SYM
+%type <num> PE_VALUE_SYM_HW
+%type <num> PE_VALUE_SYM_SW
 %type <num> PE_RAW
 %type <num> PE_TERM
 %type <str> PE_NAME
@@ -38,6 +42,7 @@ do { \
 %type <str> PE_NAME_CACHE_OP_RESULT
 %type <str> PE_MODIFIER_EVENT
 %type <str> PE_MODIFIER_BP
+%type <num> value_sym
 %type <head> event_config
 %type <term> event_term
 %type <head> event_pmu
@@ -58,24 +63,33 @@ do { \
 }
 %%
 
+start:
+PE_START_EVENTS events
+|
+PE_START_TERMS  terms
+
 events:
 events ',' event | event
 
 event:
 event_def PE_MODIFIER_EVENT
 {
+       struct parse_events_data__events *data = _data;
+
        /*
         * Apply modifier on all events added by single event definition
         * (there could be more events added for multiple tracepoint
         * definitions via '*?'.
         */
        ABORT_ON(parse_events_modifier($1, $2));
-       parse_events_update_lists($1, list_all);
+       parse_events_update_lists($1, &data->list);
 }
 |
 event_def
 {
-       parse_events_update_lists($1, list_all);
+       struct parse_events_data__events *data = _data;
+
+       parse_events_update_lists($1, &data->list);
 }
 
 event_def: event_pmu |
@@ -89,104 +103,131 @@ event_def: event_pmu |
 event_pmu:
 PE_NAME '/' event_config '/'
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
+       ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
        parse_events__free_terms($3);
        $$ = list;
 }
 
+value_sym:
+PE_VALUE_SYM_HW
+|
+PE_VALUE_SYM_SW
+
 event_legacy_symbol:
-PE_VALUE_SYM '/' event_config '/'
+value_sym '/' event_config '/'
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
        int type = $1 >> 16;
        int config = $1 & 255;
 
-       ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
+       ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+                                         type, config, $3));
        parse_events__free_terms($3);
        $$ = list;
 }
 |
-PE_VALUE_SYM sep_slash_dc
+value_sym sep_slash_dc
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
        int type = $1 >> 16;
        int config = $1 & 255;
 
-       ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
+       ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+                                         type, config, NULL));
        $$ = list;
 }
 
 event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
+       ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
        $$ = list;
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
+       ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
        $$ = list;
 }
 |
 PE_NAME_CACHE_TYPE
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
+       ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
        $$ = list;
 }
 
 event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
+       ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+                                            (void *) $2, $4));
        $$ = list;
 }
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
+       ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+                                            (void *) $2, NULL));
        $$ = list;
 }
 
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
+       ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
        $$ = list;
 }
 
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
+       ABORT_ON(parse_events_add_numeric(&list, &data->idx, $1, $3, NULL));
        $$ = list;
 }
 
 event_legacy_raw:
 PE_RAW
 {
+       struct parse_events_data__events *data = _data;
        struct list_head *list = NULL;
 
-       ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
+       ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+                                         PERF_TYPE_RAW, $1, NULL));
        $$ = list;
 }
 
+terms: event_config
+{
+       struct parse_events_data__terms *data = _data;
+       data->terms = $1;
+}
+
 event_config:
 event_config ',' event_term
 {
@@ -267,8 +308,7 @@ sep_slash_dc: '/' | ':' |
 
 %%
 
-void parse_events_error(struct list_head *list_all __used,
-                       int *idx __used,
+void parse_events_error(void *data __used, void *scanner __used,
                        char const *msg __used)
 {
 }
index a119a5371699bd1c89575ce02de0d47655548e52..67715a42cd6dc377e0056dff9590404734199d14 100644 (file)
@@ -72,7 +72,7 @@ static int pmu_format(char *name, struct list_head *format)
                 "%s/bus/event_source/devices/%s/format", sysfs, name);
 
        if (stat(path, &st) < 0)
-               return -1;
+               return 0;       /* no error if format does not exist */
 
        if (pmu_format_parse(path, format))
                return -1;
@@ -80,6 +80,114 @@ static int pmu_format(char *name, struct list_head *format)
        return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
+{
+       struct perf_pmu__alias *alias;
+       char buf[256];
+       int ret;
+
+       ret = fread(buf, 1, sizeof(buf), file);
+       if (ret == 0)
+               return -EINVAL;
+       buf[ret] = 0;
+
+       alias = malloc(sizeof(*alias));
+       if (!alias)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&alias->terms);
+       ret = parse_events_terms(&alias->terms, buf);
+       if (ret) {
+               free(alias);
+               return ret;
+       }
+
+       alias->name = strdup(name);
+       list_add_tail(&alias->list, list);
+       return 0;
+}
+
+/*
+ * Process all the sysfs attributes located under the directory
+ * specified in 'dir' parameter.
+ */
+static int pmu_aliases_parse(char *dir, struct list_head *head)
+{
+       struct dirent *evt_ent;
+       DIR *event_dir;
+       int ret = 0;
+
+       event_dir = opendir(dir);
+       if (!event_dir)
+               return -EINVAL;
+
+       while (!ret && (evt_ent = readdir(event_dir))) {
+               char path[PATH_MAX];
+               char *name = evt_ent->d_name;
+               FILE *file;
+
+               if (!strcmp(name, ".") || !strcmp(name, ".."))
+                       continue;
+
+               snprintf(path, PATH_MAX, "%s/%s", dir, name);
+
+               ret = -EINVAL;
+               file = fopen(path, "r");
+               if (!file)
+                       break;
+               ret = perf_pmu__new_alias(head, name, file);
+               fclose(file);
+       }
+
+       closedir(event_dir);
+       return ret;
+}
+
+/*
+ * Reading the pmu event aliases definition, which should be located at:
+ * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
+ */
+static int pmu_aliases(char *name, struct list_head *head)
+{
+       struct stat st;
+       char path[PATH_MAX];
+       const char *sysfs;
+
+       sysfs = sysfs_find_mountpoint();
+       if (!sysfs)
+               return -1;
+
+       snprintf(path, PATH_MAX,
+                "%s/bus/event_source/devices/%s/events", sysfs, name);
+
+       if (stat(path, &st) < 0)
+               return -1;
+
+       if (pmu_aliases_parse(path, head))
+               return -1;
+
+       return 0;
+}
+
+static int pmu_alias_terms(struct perf_pmu__alias *alias,
+                          struct list_head *terms)
+{
+       struct parse_events__term *term, *clone;
+       LIST_HEAD(list);
+       int ret;
+
+       list_for_each_entry(term, &alias->terms, list) {
+               ret = parse_events__term_clone(&clone, term);
+               if (ret) {
+                       parse_events__free_terms(&list);
+                       return ret;
+               }
+               list_add_tail(&clone->list, &list);
+       }
+       list_splice(&list, terms);
+       return 0;
+}
+
 /*
  * Reading/parsing the default pmu type value, which should be
  * located at:
@@ -118,6 +226,7 @@ static struct perf_pmu *pmu_lookup(char *name)
 {
        struct perf_pmu *pmu;
        LIST_HEAD(format);
+       LIST_HEAD(aliases);
        __u32 type;
 
        /*
@@ -135,10 +244,15 @@ static struct perf_pmu *pmu_lookup(char *name)
        if (!pmu)
                return NULL;
 
+       pmu_aliases(name, &aliases);
+
        INIT_LIST_HEAD(&pmu->format);
+       INIT_LIST_HEAD(&pmu->aliases);
        list_splice(&format, &pmu->format);
+       list_splice(&aliases, &pmu->aliases);
        pmu->name = strdup(name);
        pmu->type = type;
+       list_add_tail(&pmu->list, &pmus);
        return pmu;
 }
 
@@ -279,6 +393,59 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
        return pmu_config(&pmu->format, attr, head_terms);
 }
 
+static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
+                                             struct parse_events__term *term)
+{
+       struct perf_pmu__alias *alias;
+       char *name;
+
+       if (parse_events__is_hardcoded_term(term))
+               return NULL;
+
+       if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
+               if (term->val.num != 1)
+                       return NULL;
+               if (pmu_find_format(&pmu->format, term->config))
+                       return NULL;
+               name = term->config;
+       } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
+               if (strcasecmp(term->config, "event"))
+                       return NULL;
+               name = term->val.str;
+       } else {
+               return NULL;
+       }
+
+       list_for_each_entry(alias, &pmu->aliases, list) {
+               if (!strcasecmp(alias->name, name))
+                       return alias;
+       }
+       return NULL;
+}
+
+/*
+ * Find alias in the terms list and replace it with the terms
+ * defined for the alias
+ */
+int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
+{
+       struct parse_events__term *term, *h;
+       struct perf_pmu__alias *alias;
+       int ret;
+
+       list_for_each_entry_safe(term, h, head_terms, list) {
+               alias = pmu_find_alias(pmu, term);
+               if (!alias)
+                       continue;
+               ret = pmu_alias_terms(alias, &term->list);
+               if (ret)
+                       return ret;
+               list_del(&term->list);
+               free(term);
+       }
+       return 0;
+}
+
 int perf_pmu__new_format(struct list_head *list, char *name,
                         int config, unsigned long *bits)
 {
index 68c0db965e1f52574375859e821daacce9387a3a..535f2c5258ab05a8110727704c98791c850dc588 100644 (file)
@@ -19,17 +19,26 @@ struct perf_pmu__format {
        struct list_head list;
 };
 
+struct perf_pmu__alias {
+       char *name;
+       struct list_head terms;
+       struct list_head list;
+};
+
 struct perf_pmu {
        char *name;
        __u32 type;
        struct list_head format;
+       struct list_head aliases;
        struct list_head list;
 };
 
 struct perf_pmu *perf_pmu__find(char *name);
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
                     struct list_head *head_terms);
-
+int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
+struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
+                               struct list_head *head_terms);
 int perf_pmu_wrap(void);
 void perf_pmu_error(struct list_head *list, char *name, char const *msg);
 
index 4c1b3d72a1d2d24093733018674024e42723a548..02dfa19a467fcde82abfb0e0802a26a5579c9890 100644 (file)
@@ -209,6 +209,10 @@ static void define_event_symbols(struct event_format *event,
                define_symbolic_values(args->symbol.symbols, ev_name,
                                       cur_field_name);
                break;
+       case PRINT_HEX:
+               define_event_symbols(event, ev_name, args->hex.field);
+               define_event_symbols(event, ev_name, args->hex.size);
+               break;
        case PRINT_BSTRING:
        case PRINT_DYNAMIC_ARRAY:
        case PRINT_STRING:
@@ -233,7 +237,8 @@ static void define_event_symbols(struct event_format *event,
                define_event_symbols(event, ev_name, args->next);
 }
 
-static inline struct event_format *find_cache_event(int type)
+static inline
+struct event_format *find_cache_event(struct pevent *pevent, int type)
 {
        static char ev_name[256];
        struct event_format *event;
@@ -241,7 +246,7 @@ static inline struct event_format *find_cache_event(int type)
        if (events[type])
                return events[type];
 
-       events[type] = event = trace_find_event(type);
+       events[type] = event = pevent_find_event(pevent, type);
        if (!event)
                return NULL;
 
@@ -252,7 +257,8 @@ static inline struct event_format *find_cache_event(int type)
        return event;
 }
 
-static void perl_process_tracepoint(union perf_event *pevent __unused,
+static void perl_process_tracepoint(union perf_event *perf_event __unused,
+                                   struct pevent *pevent,
                                    struct perf_sample *sample,
                                    struct perf_evsel *evsel,
                                    struct machine *machine __unused,
@@ -275,13 +281,13 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
        if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
                return;
 
-       type = trace_parse_common_type(data);
+       type = trace_parse_common_type(pevent, data);
 
-       event = find_cache_event(type);
+       event = find_cache_event(pevent, type);
        if (!event)
                die("ug! no event found for type %d", type);
 
-       pid = trace_parse_common_pid(data);
+       pid = trace_parse_common_pid(pevent, data);
 
        sprintf(handler, "%s::%s", event->system, event->name);
 
@@ -314,7 +320,8 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
                                offset = field->offset;
                        XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
                } else { /* FIELD_IS_NUMERIC */
-                       val = read_size(data + field->offset, field->size);
+                       val = read_size(pevent, data + field->offset,
+                                       field->size);
                        if (field->flags & FIELD_IS_SIGNED) {
                                XPUSHs(sv_2mortal(newSViv(val)));
                        } else {
@@ -368,14 +375,15 @@ static void perl_process_event_generic(union perf_event *pevent __unused,
        LEAVE;
 }
 
-static void perl_process_event(union perf_event *pevent,
+static void perl_process_event(union perf_event *event,
+                              struct pevent *pevent,
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
                               struct machine *machine,
                               struct thread *thread)
 {
-       perl_process_tracepoint(pevent, sample, evsel, machine, thread);
-       perl_process_event_generic(pevent, sample, evsel, machine, thread);
+       perl_process_tracepoint(event, pevent, sample, evsel, machine, thread);
+       perl_process_event_generic(event, sample, evsel, machine, thread);
 }
 
 static void run_start_sub(void)
@@ -448,7 +456,7 @@ static int perl_stop_script(void)
        return 0;
 }
 
-static int perl_generate_script(const char *outfile)
+static int perl_generate_script(struct pevent *pevent, const char *outfile)
 {
        struct event_format *event = NULL;
        struct format_field *f;
@@ -495,7 +503,7 @@ static int perl_generate_script(const char *outfile)
        fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
        fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
 
-       while ((event = trace_find_next_event(event))) {
+       while ((event = trace_find_next_event(pevent, event))) {
                fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
                fprintf(ofp, "\tmy (");
 
index acb9795286c4bd077531fcf65f14cc8d0699a198..ce4d1b0c38626d800defaf373b231ae9171f3904 100644 (file)
@@ -166,6 +166,10 @@ static void define_event_symbols(struct event_format *event,
                define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
                              cur_field_name);
                break;
+       case PRINT_HEX:
+               define_event_symbols(event, ev_name, args->hex.field);
+               define_event_symbols(event, ev_name, args->hex.size);
+               break;
        case PRINT_STRING:
                break;
        case PRINT_TYPE:
@@ -190,7 +194,8 @@ static void define_event_symbols(struct event_format *event,
                define_event_symbols(event, ev_name, args->next);
 }
 
-static inline struct event_format *find_cache_event(int type)
+static inline
+struct event_format *find_cache_event(struct pevent *pevent, int type)
 {
        static char ev_name[256];
        struct event_format *event;
@@ -198,7 +203,7 @@ static inline struct event_format *find_cache_event(int type)
        if (events[type])
                return events[type];
 
-       events[type] = event = trace_find_event(type);
+       events[type] = event = pevent_find_event(pevent, type);
        if (!event)
                return NULL;
 
@@ -209,7 +214,8 @@ static inline struct event_format *find_cache_event(int type)
        return event;
 }
 
-static void python_process_event(union perf_event *pevent __unused,
+static void python_process_event(union perf_event *perf_event __unused,
+                                struct pevent *pevent,
                                 struct perf_sample *sample,
                                 struct perf_evsel *evsel __unused,
                                 struct machine *machine __unused,
@@ -233,13 +239,13 @@ static void python_process_event(union perf_event *pevent __unused,
        if (!t)
                Py_FatalError("couldn't create Python tuple");
 
-       type = trace_parse_common_type(data);
+       type = trace_parse_common_type(pevent, data);
 
-       event = find_cache_event(type);
+       event = find_cache_event(pevent, type);
        if (!event)
                die("ug! no event found for type %d", type);
 
-       pid = trace_parse_common_pid(data);
+       pid = trace_parse_common_pid(pevent, data);
 
        sprintf(handler_name, "%s__%s", event->system, event->name);
 
@@ -284,7 +290,8 @@ static void python_process_event(union perf_event *pevent __unused,
                                offset = field->offset;
                        obj = PyString_FromString((char *)data + offset);
                } else { /* FIELD_IS_NUMERIC */
-                       val = read_size(data + field->offset, field->size);
+                       val = read_size(pevent, data + field->offset,
+                                       field->size);
                        if (field->flags & FIELD_IS_SIGNED) {
                                if ((long long)val >= LONG_MIN &&
                                    (long long)val <= LONG_MAX)
@@ -438,7 +445,7 @@ out:
        return err;
 }
 
-static int python_generate_script(const char *outfile)
+static int python_generate_script(struct pevent *pevent, const char *outfile)
 {
        struct event_format *event = NULL;
        struct format_field *f;
@@ -487,7 +494,7 @@ static int python_generate_script(const char *outfile)
        fprintf(ofp, "def trace_end():\n");
        fprintf(ofp, "\tprint \"in trace_end\"\n\n");
 
-       while ((event = trace_find_next_event(event))) {
+       while ((event = trace_find_next_event(pevent, event))) {
                fprintf(ofp, "def %s__%s(", event->system, event->name);
                fprintf(ofp, "event_name, ");
                fprintf(ofp, "context, ");
index c3e399bcf18deea25f4db0aafa69278b5b4cb570..8e485592ca200c1712d1c959296230f9dce50d33 100644 (file)
@@ -14,6 +14,7 @@
 #include "sort.h"
 #include "util.h"
 #include "cpumap.h"
+#include "event-parse.h"
 
 static int perf_session__open(struct perf_session *self, bool force)
 {
@@ -289,7 +290,6 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
 }
 
 int machine__resolve_callchain(struct machine *self,
-                              struct perf_evsel *evsel __used,
                               struct thread *thread,
                               struct ip_callchain *chain,
                               struct symbol **parent)
@@ -926,7 +926,7 @@ static struct machine *
                else
                        pid = event->ip.pid;
 
-               return perf_session__find_machine(session, pid);
+               return perf_session__findnew_machine(session, pid);
        }
 
        return perf_session__find_host_machine(session);
@@ -1449,7 +1449,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
        ret += hists__fprintf_nr_events(&session->hists, fp);
 
        list_for_each_entry(pos, &session->evlist->entries, node) {
-               ret += fprintf(fp, "%s stats:\n", event_name(pos));
+               ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
                ret += hists__fprintf_nr_events(&pos->hists, fp);
        }
 
@@ -1490,8 +1490,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
 }
 
 void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
-                         struct machine *machine, struct perf_evsel *evsel,
-                         int print_sym, int print_dso, int print_symoffset)
+                         struct machine *machine, int print_sym,
+                         int print_dso, int print_symoffset)
 {
        struct addr_location al;
        struct callchain_cursor_node *node;
@@ -1505,7 +1505,7 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
 
        if (symbol_conf.use_callchain && sample->callchain) {
 
-               if (machine__resolve_callchain(machine, evsel, al.thread,
+               if (machine__resolve_callchain(machine, al.thread,
                                                sample->callchain, NULL) != 0) {
                        if (verbose)
                                error("Failed to resolve callchain. Skipping\n");
@@ -1611,3 +1611,58 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
        perf_header__fprintf_info(session, fp, full);
        fprintf(fp, "# ========\n#\n");
 }
+
+
+int __perf_session__set_tracepoints_handlers(struct perf_session *session,
+                                            const struct perf_evsel_str_handler *assocs,
+                                            size_t nr_assocs)
+{
+       struct perf_evlist *evlist = session->evlist;
+       struct event_format *format;
+       struct perf_evsel *evsel;
+       char *tracepoint, *name;
+       size_t i;
+       int err;
+
+       for (i = 0; i < nr_assocs; i++) {
+               err = -ENOMEM;
+               tracepoint = strdup(assocs[i].name);
+               if (tracepoint == NULL)
+                       goto out;
+
+               err = -ENOENT;
+               name = strchr(tracepoint, ':');
+               if (name == NULL)
+                       goto out_free;
+
+               *name++ = '\0';
+               format = pevent_find_event_by_name(session->pevent,
+                                                  tracepoint, name);
+               if (format == NULL) {
+                       /*
+                        * Adding a handler for an event not in the session,
+                        * just ignore it.
+                        */
+                       goto next;
+               }
+
+               evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id);
+               if (evsel == NULL)
+                       goto next;
+
+               err = -EEXIST;
+               if (evsel->handler.func != NULL)
+                       goto out_free;
+               evsel->handler.func = assocs[i].handler;
+next:
+               free(tracepoint);
+       }
+
+       err = 0;
+out:
+       return err;
+
+out_free:
+       free(tracepoint);
+       goto out;
+}
index 0c702e3f0a364272a9d979b04786403c4e079bbe..7c435bde6eb0ea1f913e1dadfca3da0c23432302 100644 (file)
@@ -33,6 +33,7 @@ struct perf_session {
        struct machine          host_machine;
        struct rb_root          machines;
        struct perf_evlist      *evlist;
+       struct pevent           *pevent;
        /*
         * FIXME: Need to split this up further, we need global
         *        stats + per event stats. 'perf diff' also needs
@@ -151,11 +152,20 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
                                            unsigned int type);
 
 void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
-                         struct machine *machine, struct perf_evsel *evsel,
-                         int print_sym, int print_dso, int print_symoffset);
+                         struct machine *machine, int print_sym,
+                         int print_dso, int print_symoffset);
 
 int perf_session__cpu_bitmap(struct perf_session *session,
                             const char *cpu_list, unsigned long *cpu_bitmap);
 
 void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
+
+struct perf_evsel_str_handler;
+
+int __perf_session__set_tracepoints_handlers(struct perf_session *session,
+                                            const struct perf_evsel_str_handler *assocs,
+                                            size_t nr_assocs);
+
+#define perf_session__set_tracepoints_handlers(session, array) \
+       __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array))
 #endif /* __PERF_SESSION_H */
index a27237430c5f1a8b9fd24458609cc405eff9ac73..0f5a0a496bc491e545d3bf30e8820163fbba61c6 100644 (file)
@@ -241,6 +241,54 @@ struct sort_entry sort_sym = {
        .se_width_idx   = HISTC_SYMBOL,
 };
 
+/* --sort srcline */
+
+static int64_t
+sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return (int64_t)(right->ip - left->ip);
+}
+
+static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
+                                  size_t size, unsigned int width __used)
+{
+       FILE *fp;
+       char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
+       size_t line_len;
+
+       if (path != NULL)
+               goto out_path;
+
+       snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
+                self->ms.map->dso->long_name, self->ip);
+       fp = popen(cmd, "r");
+       if (!fp)
+               goto out_ip;
+
+       if (getline(&path, &line_len, fp) < 0 || !line_len)
+               goto out_ip;
+       fclose(fp);
+       self->srcline = strdup(path);
+       if (self->srcline == NULL)
+               goto out_ip;
+
+       nl = strchr(self->srcline, '\n');
+       if (nl != NULL)
+               *nl = '\0';
+       path = self->srcline;
+out_path:
+       return repsep_snprintf(bf, size, "%s", path);
+out_ip:
+       return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
+}
+
+struct sort_entry sort_srcline = {
+       .se_header      = "Source:Line",
+       .se_cmp         = sort__srcline_cmp,
+       .se_snprintf    = hist_entry__srcline_snprintf,
+       .se_width_idx   = HISTC_SRCLINE,
+};
+
 /* --sort parent */
 
 static int64_t
@@ -439,6 +487,7 @@ static struct sort_dimension sort_dimensions[] = {
        DIM(SORT_PARENT, "parent", sort_parent),
        DIM(SORT_CPU, "cpu", sort_cpu),
        DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
+       DIM(SORT_SRCLINE, "srcline", sort_srcline),
 };
 
 int sort_dimension__add(const char *tok)
index 472aa5a63a58f571fccd884f1e7f16f08b3b5ec7..e724b26acd5135e609aca16212edaf7ec56a9da4 100644 (file)
@@ -71,6 +71,7 @@ struct hist_entry {
        char                    level;
        bool                    used;
        u8                      filtered;
+       char                    *srcline;
        struct symbol           *parent;
        union {
                unsigned long     position;
@@ -93,6 +94,7 @@ enum sort_type {
        SORT_SYM_FROM,
        SORT_SYM_TO,
        SORT_MISPREDICT,
+       SORT_SRCLINE,
 };
 
 /*
index d5836382ff2cad7d00fd156d1296f99f8433f698..199bc4d8905d4ff75d31a60471673fac68470aec 100644 (file)
@@ -313,3 +313,25 @@ int strtailcmp(const char *s1, const char *s2)
        return 0;
 }
 
+/**
+ * rtrim - Removes trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns @s.
+ */
+char *rtrim(char *s)
+{
+       size_t size = strlen(s);
+       char *end;
+
+       if (!size)
+               return s;
+
+       end = s + size - 1;
+       while (end >= s && isspace(*end))
+               end--;
+       *(end + 1) = '\0';
+
+       return s;
+}
index 3e2e5ea0f03f692c41f62e8aeb1f5d3382c86ce1..50958bbeb26aa0c0d19f92deb830649cd43d5100 100644 (file)
@@ -1478,14 +1478,31 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
                goto out;
        }
 
-       sec = elf_section_by_name(elf, &ehdr, &shdr,
-                                 ".note.gnu.build-id", NULL);
-       if (sec == NULL) {
+       /*
+        * Check following sections for notes:
+        *   '.note.gnu.build-id'
+        *   '.notes'
+        *   '.note' (VDSO specific)
+        */
+       do {
+               sec = elf_section_by_name(elf, &ehdr, &shdr,
+                                         ".note.gnu.build-id", NULL);
+               if (sec)
+                       break;
+
                sec = elf_section_by_name(elf, &ehdr, &shdr,
                                          ".notes", NULL);
-               if (sec == NULL)
-                       goto out;
-       }
+               if (sec)
+                       break;
+
+               sec = elf_section_by_name(elf, &ehdr, &shdr,
+                                         ".note", NULL);
+               if (sec)
+                       break;
+
+               return err;
+
+       } while (0);
 
        data = elf_getdata(sec, NULL);
        if (data == NULL)
@@ -1590,11 +1607,62 @@ out:
        return err;
 }
 
+static int filename__read_debuglink(const char *filename,
+                                   char *debuglink, size_t size)
+{
+       int fd, err = -1;
+       Elf *elf;
+       GElf_Ehdr ehdr;
+       GElf_Shdr shdr;
+       Elf_Data *data;
+       Elf_Scn *sec;
+       Elf_Kind ek;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               goto out;
+
+       elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+       if (elf == NULL) {
+               pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
+               goto out_close;
+       }
+
+       ek = elf_kind(elf);
+       if (ek != ELF_K_ELF)
+               goto out_close;
+
+       if (gelf_getehdr(elf, &ehdr) == NULL) {
+               pr_err("%s: cannot get elf header.\n", __func__);
+               goto out_close;
+       }
+
+       sec = elf_section_by_name(elf, &ehdr, &shdr,
+                                 ".gnu_debuglink", NULL);
+       if (sec == NULL)
+               goto out_close;
+
+       data = elf_getdata(sec, NULL);
+       if (data == NULL)
+               goto out_close;
+
+       /* the start of this section is a zero-terminated string */
+       strncpy(debuglink, data->d_buf, size);
+
+       elf_end(elf);
+
+out_close:
+       close(fd);
+out:
+       return err;
+}
+
 char dso__symtab_origin(const struct dso *dso)
 {
        static const char origin[] = {
                [SYMTAB__KALLSYMS]            = 'k',
                [SYMTAB__JAVA_JIT]            = 'j',
+               [SYMTAB__DEBUGLINK]           = 'l',
                [SYMTAB__BUILD_ID_CACHE]      = 'B',
                [SYMTAB__FEDORA_DEBUGINFO]    = 'f',
                [SYMTAB__UBUNTU_DEBUGINFO]    = 'u',
@@ -1662,10 +1730,22 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
         */
        want_symtab = 1;
 restart:
-       for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE;
+       for (dso->symtab_type = SYMTAB__DEBUGLINK;
             dso->symtab_type != SYMTAB__NOT_FOUND;
             dso->symtab_type++) {
                switch (dso->symtab_type) {
+               case SYMTAB__DEBUGLINK: {
+                       char *debuglink;
+                       strncpy(name, dso->long_name, size);
+                       debuglink = name + dso->long_name_len;
+                       while (debuglink != name && *debuglink != '/')
+                               debuglink--;
+                       if (*debuglink == '/')
+                               debuglink++;
+                       filename__read_debuglink(dso->long_name, debuglink,
+                                                size - (debuglink - name));
+                       }
+                       break;
                case SYMTAB__BUILD_ID_CACHE:
                        /* skip the locally configured cache if a symfs is given */
                        if (symbol_conf.symfs[0] ||
index af0752b1aca1a9097b1eb552da416683bf3394c7..a884b99017f085c0dceb47e7b766dab8527dc7df 100644 (file)
@@ -257,6 +257,7 @@ enum symtab_type {
        SYMTAB__KALLSYMS = 0,
        SYMTAB__GUEST_KALLSYMS,
        SYMTAB__JAVA_JIT,
+       SYMTAB__DEBUGLINK,
        SYMTAB__BUILD_ID_CACHE,
        SYMTAB__FEDORA_DEBUGINFO,
        SYMTAB__UBUNTU_DEBUGINFO,
index abe0e8e9506820ac4d5e5b9f2b08c89ffde49b73..7eeebcee291c4c70a8e0bc0dc0371d107080a1d9 100644 (file)
@@ -65,7 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
                                top->freq ? "Hz" : "");
        }
 
-       ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
+       ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
 
        ret += SNPRINTF(bf + ret, size - ret, "], ");
 
index df2fddbf0cd2f46d376d691786295526fa1deab0..0715c843c2e73ad6fc61832854cb33571732a73f 100644 (file)
@@ -32,29 +32,25 @@ int header_page_size_size;
 int header_page_ts_size;
 int header_page_data_offset;
 
-struct pevent *perf_pevent;
-static struct pevent *pevent;
-
 bool latency_format;
 
-int read_trace_init(int file_bigendian, int host_bigendian)
+struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
 {
-       if (pevent)
-               return 0;
-
-       perf_pevent = pevent_alloc();
-       pevent = perf_pevent;
+       struct pevent *pevent = pevent_alloc();
 
-       pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
-       pevent_set_file_bigendian(pevent, file_bigendian);
-       pevent_set_host_bigendian(pevent, host_bigendian);
+       if (pevent != NULL) {
+               pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
+               pevent_set_file_bigendian(pevent, file_bigendian);
+               pevent_set_host_bigendian(pevent, host_bigendian);
+       }
 
-       return 0;
+       return pevent;
 }
 
 static int get_common_field(struct scripting_context *context,
                            int *offset, int *size, const char *type)
 {
+       struct pevent *pevent = context->pevent;
        struct event_format *event;
        struct format_field *field;
 
@@ -150,7 +146,7 @@ void *raw_field_ptr(struct event_format *event, const char *name, void *data)
        return data + field->offset;
 }
 
-int trace_parse_common_type(void *data)
+int trace_parse_common_type(struct pevent *pevent, void *data)
 {
        struct pevent_record record;
 
@@ -158,7 +154,7 @@ int trace_parse_common_type(void *data)
        return pevent_data_type(pevent, &record);
 }
 
-int trace_parse_common_pid(void *data)
+int trace_parse_common_pid(struct pevent *pevent, void *data)
 {
        struct pevent_record record;
 
@@ -166,27 +162,21 @@ int trace_parse_common_pid(void *data)
        return pevent_data_pid(pevent, &record);
 }
 
-unsigned long long read_size(void *ptr, int size)
+unsigned long long read_size(struct pevent *pevent, void *ptr, int size)
 {
        return pevent_read_number(pevent, ptr, size);
 }
 
-struct event_format *trace_find_event(int type)
-{
-       return pevent_find_event(pevent, type);
-}
-
-
-void print_trace_event(int cpu, void *data, int size)
+void print_trace_event(struct pevent *pevent, int cpu, void *data, int size)
 {
        struct event_format *event;
        struct pevent_record record;
        struct trace_seq s;
        int type;
 
-       type = trace_parse_common_type(data);
+       type = trace_parse_common_type(pevent, data);
 
-       event = trace_find_event(type);
+       event = pevent_find_event(pevent, type);
        if (!event) {
                warning("ug! no event found for type %d", type);
                return;
@@ -198,13 +188,12 @@ void print_trace_event(int cpu, void *data, int size)
        record.data = data;
 
        trace_seq_init(&s);
-       pevent_print_event(pevent, &s, &record);
+       pevent_event_info(&s, event, &record);
        trace_seq_do_printf(&s);
-       printf("\n");
 }
 
-void print_event(int cpu, void *data, int size, unsigned long long nsecs,
-                 char *comm)
+void print_event(struct pevent *pevent, int cpu, void *data, int size,
+                unsigned long long nsecs, char *comm)
 {
        struct pevent_record record;
        struct trace_seq s;
@@ -227,7 +216,8 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
        printf("\n");
 }
 
-void parse_proc_kallsyms(char *file, unsigned int size __unused)
+void parse_proc_kallsyms(struct pevent *pevent,
+                        char *file, unsigned int size __unused)
 {
        unsigned long long addr;
        char *func;
@@ -258,7 +248,8 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
        }
 }
 
-void parse_ftrace_printk(char *file, unsigned int size __unused)
+void parse_ftrace_printk(struct pevent *pevent,
+                        char *file, unsigned int size __unused)
 {
        unsigned long long addr;
        char *printk;
@@ -282,17 +273,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
        }
 }
 
-int parse_ftrace_file(char *buf, unsigned long size)
+int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size)
 {
        return pevent_parse_event(pevent, buf, size, "ftrace");
 }
 
-int parse_event_file(char *buf, unsigned long size, char *sys)
+int parse_event_file(struct pevent *pevent,
+                    char *buf, unsigned long size, char *sys)
 {
        return pevent_parse_event(pevent, buf, size, sys);
 }
 
-struct event_format *trace_find_next_event(struct event_format *event)
+struct event_format *trace_find_next_event(struct pevent *pevent,
+                                          struct event_format *event)
 {
        static int idx;
 
index f097e0dd6c5cb4986aa1e5cd1a1cb61cdca55cdf..719ed74a85652541d19e1f7dc15d26e2348a31fc 100644 (file)
@@ -114,20 +114,20 @@ static void skip(int size)
        };
 }
 
-static unsigned int read4(void)
+static unsigned int read4(struct pevent *pevent)
 {
        unsigned int data;
 
        read_or_die(&data, 4);
-       return __data2host4(perf_pevent, data);
+       return __data2host4(pevent, data);
 }
 
-static unsigned long long read8(void)
+static unsigned long long read8(struct pevent *pevent)
 {
        unsigned long long data;
 
        read_or_die(&data, 8);
-       return __data2host8(perf_pevent, data);
+       return __data2host8(pevent, data);
 }
 
 static char *read_string(void)
@@ -168,12 +168,12 @@ static char *read_string(void)
        return str;
 }
 
-static void read_proc_kallsyms(void)
+static void read_proc_kallsyms(struct pevent *pevent)
 {
        unsigned int size;
        char *buf;
 
-       size = read4();
+       size = read4(pevent);
        if (!size)
                return;
 
@@ -181,29 +181,29 @@ static void read_proc_kallsyms(void)
        read_or_die(buf, size);
        buf[size] = '\0';
 
-       parse_proc_kallsyms(buf, size);
+       parse_proc_kallsyms(pevent, buf, size);
 
        free(buf);
 }
 
-static void read_ftrace_printk(void)
+static void read_ftrace_printk(struct pevent *pevent)
 {
        unsigned int size;
        char *buf;
 
-       size = read4();
+       size = read4(pevent);
        if (!size)
                return;
 
        buf = malloc_or_die(size);
        read_or_die(buf, size);
 
-       parse_ftrace_printk(buf, size);
+       parse_ftrace_printk(pevent, buf, size);
 
        free(buf);
 }
 
-static void read_header_files(void)
+static void read_header_files(struct pevent *pevent)
 {
        unsigned long long size;
        char *header_event;
@@ -214,7 +214,7 @@ static void read_header_files(void)
        if (memcmp(buf, "header_page", 12) != 0)
                die("did not read header page");
 
-       size = read8();
+       size = read8(pevent);
        skip(size);
 
        /*
@@ -227,47 +227,48 @@ static void read_header_files(void)
        if (memcmp(buf, "header_event", 13) != 0)
                die("did not read header event");
 
-       size = read8();
+       size = read8(pevent);
        header_event = malloc_or_die(size);
        read_or_die(header_event, size);
        free(header_event);
 }
 
-static void read_ftrace_file(unsigned long long size)
+static void read_ftrace_file(struct pevent *pevent, unsigned long long size)
 {
        char *buf;
 
        buf = malloc_or_die(size);
        read_or_die(buf, size);
-       parse_ftrace_file(buf, size);
+       parse_ftrace_file(pevent, buf, size);
        free(buf);
 }
 
-static void read_event_file(char *sys, unsigned long long size)
+static void read_event_file(struct pevent *pevent, char *sys,
+                           unsigned long long size)
 {
        char *buf;
 
        buf = malloc_or_die(size);
        read_or_die(buf, size);
-       parse_event_file(buf, size, sys);
+       parse_event_file(pevent, buf, size, sys);
        free(buf);
 }
 
-static void read_ftrace_files(void)
+static void read_ftrace_files(struct pevent *pevent)
 {
        unsigned long long size;
        int count;
        int i;
 
-       count = read4();
+       count = read4(pevent);
 
        for (i = 0; i < count; i++) {
-               size = read8();
-               read_ftrace_file(size);
+               size = read8(pevent);
+               read_ftrace_file(pevent, size);
        }
 }
 
-static void read_event_files(void)
+static void read_event_files(struct pevent *pevent)
 {
        unsigned long long size;
        char *sys;
@@ -275,15 +276,15 @@ static void read_event_files(void)
        int count;
        int i,x;
 
-       systems = read4();
+       systems = read4(pevent);
 
        for (i = 0; i < systems; i++) {
                sys = read_string();
 
-               count = read4();
+               count = read4(pevent);
                for (x=0; x < count; x++) {
-                       size = read8();
-                       read_event_file(sys, size);
+                       size = read8(pevent);
+                       read_event_file(pevent, sys, size);
                }
        }
 }
@@ -377,7 +378,7 @@ static int calc_index(void *ptr, int cpu)
        return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
 }
 
-struct pevent_record *trace_peek_data(int cpu)
+struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu)
 {
        struct pevent_record *data;
        void *page = cpu_data[cpu].page;
@@ -399,15 +400,15 @@ struct pevent_record *trace_peek_data(int cpu)
                /* FIXME: handle header page */
                if (header_page_ts_size != 8)
                        die("expected a long long type for timestamp");
-               cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);
+               cpu_data[cpu].timestamp = data2host8(pevent, ptr);
                ptr += 8;
                switch (header_page_size_size) {
                case 4:
-                       cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);
+                       cpu_data[cpu].page_size = data2host4(pevent, ptr);
                        ptr += 4;
                        break;
                case 8:
-                       cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);
+                       cpu_data[cpu].page_size = data2host8(pevent, ptr);
                        ptr += 8;
                        break;
                default:
@@ -421,10 +422,10 @@ read_again:
 
        if (idx >= cpu_data[cpu].page_size) {
                get_next_page(cpu);
-               return trace_peek_data(cpu);
+               return trace_peek_data(pevent, cpu);
        }
 
-       type_len_ts = data2host4(perf_pevent, ptr);
+       type_len_ts = data2host4(pevent, ptr);
        ptr += 4;
 
        type_len = type_len4host(type_len_ts);
@@ -434,14 +435,14 @@ read_again:
        case RINGBUF_TYPE_PADDING:
                if (!delta)
                        die("error, hit unexpected end of page");
-               length = data2host4(perf_pevent, ptr);
+               length = data2host4(pevent, ptr);
                ptr += 4;
                length *= 4;
                ptr += length;
                goto read_again;
 
        case RINGBUF_TYPE_TIME_EXTEND:
-               extend = data2host4(perf_pevent, ptr);
+               extend = data2host4(pevent, ptr);
                ptr += 4;
                extend <<= TS_SHIFT;
                extend += delta;
@@ -452,7 +453,7 @@ read_again:
                ptr += 12;
                break;
        case 0:
-               length = data2host4(perf_pevent, ptr);
+               length = data2host4(pevent, ptr);
                ptr += 4;
                die("here! length=%d", length);
                break;
@@ -477,17 +478,17 @@ read_again:
        return data;
 }
 
-struct pevent_record *trace_read_data(int cpu)
+struct pevent_record *trace_read_data(struct pevent *pevent, int cpu)
 {
        struct pevent_record *data;
 
-       data = trace_peek_data(cpu);
+       data = trace_peek_data(pevent, cpu);
        cpu_data[cpu].next = NULL;
 
        return data;
 }
 
-ssize_t trace_report(int fd, bool __repipe)
+ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
 {
        char buf[BUFSIZ];
        char test[] = { 23, 8, 68 };
@@ -519,30 +520,32 @@ ssize_t trace_report(int fd, bool __repipe)
        file_bigendian = buf[0];
        host_bigendian = bigendian();
 
-       read_trace_init(file_bigendian, host_bigendian);
+       *ppevent = read_trace_init(file_bigendian, host_bigendian);
+       if (*ppevent == NULL)
+               die("read_trace_init failed");
 
        read_or_die(buf, 1);
        long_size = buf[0];
 
-       page_size = read4();
+       page_size = read4(*ppevent);
 
-       read_header_files();
+       read_header_files(*ppevent);
 
-       read_ftrace_files();
-       read_event_files();
-       read_proc_kallsyms();
-       read_ftrace_printk();
+       read_ftrace_files(*ppevent);
+       read_event_files(*ppevent);
+       read_proc_kallsyms(*ppevent);
+       read_ftrace_printk(*ppevent);
 
        size = calc_data_size - 1;
        calc_data_size = 0;
        repipe = false;
 
        if (show_funcs) {
-               pevent_print_funcs(perf_pevent);
+               pevent_print_funcs(*ppevent);
                return size;
        }
        if (show_printk) {
-               pevent_print_printk(perf_pevent);
+               pevent_print_printk(*ppevent);
                return size;
        }
 
index 18ae6c1831d3896263c5a7c3ff58f264bcefbfa5..474aa7a7df43e178717c7808c2ee279c4d026fb2 100644 (file)
@@ -36,6 +36,7 @@ static int stop_script_unsupported(void)
 }
 
 static void process_event_unsupported(union perf_event *event __unused,
+                                     struct pevent *pevent __unused,
                                      struct perf_sample *sample __unused,
                                      struct perf_evsel *evsel __unused,
                                      struct machine *machine __unused,
@@ -61,7 +62,8 @@ static int python_start_script_unsupported(const char *script __unused,
        return -1;
 }
 
-static int python_generate_script_unsupported(const char *outfile __unused)
+static int python_generate_script_unsupported(struct pevent *pevent __unused,
+                                             const char *outfile __unused)
 {
        print_python_unsupported_msg();
 
@@ -122,7 +124,8 @@ static int perl_start_script_unsupported(const char *script __unused,
        return -1;
 }
 
-static int perl_generate_script_unsupported(const char *outfile __unused)
+static int perl_generate_script_unsupported(struct pevent *pevent __unused,
+                                           const char *outfile __unused)
 {
        print_perl_unsupported_msg();
 
index 639852ac1117109849adc8386c66efbf0ccba24f..8fef1d6687b73250a24e682b4c41a9fb29384421 100644 (file)
@@ -8,6 +8,7 @@
 struct machine;
 struct perf_sample;
 union perf_event;
+struct perf_tool;
 struct thread;
 
 extern int header_page_size_size;
@@ -29,35 +30,36 @@ enum {
 
 int bigendian(void);
 
-int read_trace_init(int file_bigendian, int host_bigendian);
-void print_trace_event(int cpu, void *data, int size);
+struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
+void print_trace_event(struct pevent *pevent, int cpu, void *data, int size);
 
-void print_event(int cpu, void *data, int size, unsigned long long nsecs,
-                 char *comm);
+void print_event(struct pevent *pevent, int cpu, void *data, int size,
+                unsigned long long nsecs, char *comm);
 
-int parse_ftrace_file(char *buf, unsigned long size);
-int parse_event_file(char *buf, unsigned long size, char *sys);
+int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
+int parse_event_file(struct pevent *pevent,
+                    char *buf, unsigned long size, char *sys);
 
-struct pevent_record *trace_peek_data(int cpu);
-struct event_format *trace_find_event(int type);
+struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu);
 
 unsigned long long
 raw_field_value(struct event_format *event, const char *name, void *data);
 void *raw_field_ptr(struct event_format *event, const char *name, void *data);
 
-void parse_proc_kallsyms(char *file, unsigned int size __unused);
-void parse_ftrace_printk(char *file, unsigned int size __unused);
+void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
+void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
 
-ssize_t trace_report(int fd, bool repipe);
+ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
 
-int trace_parse_common_type(void *data);
-int trace_parse_common_pid(void *data);
+int trace_parse_common_type(struct pevent *pevent, void *data);
+int trace_parse_common_pid(struct pevent *pevent, void *data);
 
-struct event_format *trace_find_next_event(struct event_format *event);
-unsigned long long read_size(void *ptr, int size);
+struct event_format *trace_find_next_event(struct pevent *pevent,
+                                          struct event_format *event);
+unsigned long long read_size(struct pevent *pevent, void *ptr, int size);
 unsigned long long eval_flag(const char *flag);
 
-struct pevent_record *trace_read_data(int cpu);
+struct pevent_record *trace_read_data(struct pevent *pevent, int cpu);
 int read_tracing_data(int fd, struct list_head *pattrs);
 
 struct tracing_data {
@@ -77,11 +79,12 @@ struct scripting_ops {
        int (*start_script) (const char *script, int argc, const char **argv);
        int (*stop_script) (void);
        void (*process_event) (union perf_event *event,
+                              struct pevent *pevent,
                               struct perf_sample *sample,
                               struct perf_evsel *evsel,
                               struct machine *machine,
                               struct thread *thread);
-       int (*generate_script) (const char *outfile);
+       int (*generate_script) (struct pevent *pevent, const char *outfile);
 };
 
 int script_spec_register(const char *spec, struct scripting_ops *ops);
@@ -90,6 +93,7 @@ void setup_perl_scripting(void);
 void setup_python_scripting(void);
 
 struct scripting_context {
+       struct pevent *pevent;
        void *event_data;
 };
 
index 2daaedb83d8425c5e87077f05f2712d865b49368..b13c7331eaf8cbf89a8a1b6626238e44ab84d657 100644 (file)
@@ -264,4 +264,6 @@ bool is_power_of_2(unsigned long n)
 
 size_t hex_width(u64 v);
 
+char *rtrim(char *s);
+
 #endif
index b1e091ae2f377bcecd5fadc417776081d88aba53..23a41a9f8db999f4b70fd4c0cd4b6ae8b26ee3c2 100644 (file)
@@ -334,6 +334,11 @@ static int assigned_device_enable_host_intx(struct kvm *kvm,
 }
 
 #ifdef __KVM_HAVE_MSI
+static irqreturn_t kvm_assigned_dev_msi(int irq, void *dev_id)
+{
+       return IRQ_WAKE_THREAD;
+}
+
 static int assigned_device_enable_host_msi(struct kvm *kvm,
                                           struct kvm_assigned_dev_kernel *dev)
 {
@@ -346,7 +351,7 @@ static int assigned_device_enable_host_msi(struct kvm *kvm,
        }
 
        dev->host_irq = dev->dev->irq;
-       if (request_threaded_irq(dev->host_irq, NULL,
+       if (request_threaded_irq(dev->host_irq, kvm_assigned_dev_msi,
                                 kvm_assigned_dev_thread_msi, 0,
                                 dev->irq_name, dev)) {
                pci_disable_msi(dev->dev);
@@ -358,6 +363,11 @@ static int assigned_device_enable_host_msi(struct kvm *kvm,
 #endif
 
 #ifdef __KVM_HAVE_MSIX
+static irqreturn_t kvm_assigned_dev_msix(int irq, void *dev_id)
+{
+       return IRQ_WAKE_THREAD;
+}
+
 static int assigned_device_enable_host_msix(struct kvm *kvm,
                                            struct kvm_assigned_dev_kernel *dev)
 {
@@ -374,7 +384,8 @@ static int assigned_device_enable_host_msix(struct kvm *kvm,
 
        for (i = 0; i < dev->entries_nr; i++) {
                r = request_threaded_irq(dev->host_msix_entries[i].vector,
-                                        NULL, kvm_assigned_dev_thread_msix,
+                                        kvm_assigned_dev_msix,
+                                        kvm_assigned_dev_thread_msix,
                                         0, dev->irq_name, dev);
                if (r)
                        goto err;
index f59c1e8de7a2e62b5977d90ab992e1c2240e80f5..7d7e2aaffece234a81cef3f4181cc7ffe5bb14cb 100644 (file)
@@ -198,7 +198,7 @@ static void irqfd_update(struct kvm *kvm, struct _irqfd *irqfd,
 }
 
 static int
-kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
+kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
 {
        struct kvm_irq_routing_table *irq_rt;
        struct _irqfd *irqfd, *tmp;
@@ -212,12 +212,12 @@ kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
                return -ENOMEM;
 
        irqfd->kvm = kvm;
-       irqfd->gsi = gsi;
+       irqfd->gsi = args->gsi;
        INIT_LIST_HEAD(&irqfd->list);
        INIT_WORK(&irqfd->inject, irqfd_inject);
        INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
 
-       file = eventfd_fget(fd);
+       file = eventfd_fget(args->fd);
        if (IS_ERR(file)) {
                ret = PTR_ERR(file);
                goto fail;
@@ -298,19 +298,19 @@ kvm_eventfd_init(struct kvm *kvm)
  * shutdown any irqfd's that match fd+gsi
  */
 static int
-kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi)
+kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args)
 {
        struct _irqfd *irqfd, *tmp;
        struct eventfd_ctx *eventfd;
 
-       eventfd = eventfd_ctx_fdget(fd);
+       eventfd = eventfd_ctx_fdget(args->fd);
        if (IS_ERR(eventfd))
                return PTR_ERR(eventfd);
 
        spin_lock_irq(&kvm->irqfds.lock);
 
        list_for_each_entry_safe(irqfd, tmp, &kvm->irqfds.items, list) {
-               if (irqfd->eventfd == eventfd && irqfd->gsi == gsi) {
+               if (irqfd->eventfd == eventfd && irqfd->gsi == args->gsi) {
                        /*
                         * This rcu_assign_pointer is needed for when
                         * another thread calls kvm_irq_routing_update before
@@ -338,12 +338,15 @@ kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi)
 }
 
 int
-kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
+kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
 {
-       if (flags & KVM_IRQFD_FLAG_DEASSIGN)
-               return kvm_irqfd_deassign(kvm, fd, gsi);
+       if (args->flags & ~KVM_IRQFD_FLAG_DEASSIGN)
+               return -EINVAL;
+
+       if (args->flags & KVM_IRQFD_FLAG_DEASSIGN)
+               return kvm_irqfd_deassign(kvm, args);
 
-       return kvm_irqfd_assign(kvm, fd, gsi);
+       return kvm_irqfd_assign(kvm, args);
 }
 
 /*
index 7e140683ff14d503a9714058cadd9dde7e4ffaf9..44ee7124b16dae1820ca1ca1c79f2a099979da12 100644 (file)
@@ -2047,7 +2047,7 @@ static long kvm_vm_ioctl(struct file *filp,
                r = -EFAULT;
                if (copy_from_user(&data, argp, sizeof data))
                        goto out;
-               r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
+               r = kvm_irqfd(kvm, &data);
                break;
        }
        case KVM_IOEVENTFD: {
@@ -2845,6 +2845,7 @@ void kvm_exit(void)
        kvm_arch_hardware_unsetup();
        kvm_arch_exit();
        free_cpumask_var(cpus_hardware_enabled);
+       __free_page(fault_page);
        __free_page(hwpoison_page);
        __free_page(bad_page);
 }